4
\$\begingroup\$

I decided to learn J so that I could better take part in code golfing. Starting it off relatively simple, I tried writing a solution to this problem:

Find the sum of all the multiples of 3 or 5 below 1000.

After a bit of tinkering, I came up with the following J code that solves it:

x=:i.1000
+/x#(0=3|x)+.0=5|x

Basically, what I'm doing is taking two lists of numbers from 1 to 1000, and finding one modulo 3, and the other modulo 5. Then I OR them together to get a list of indicies where a number is divisible by either 3 or 5. I then use that to sum the numbers.

What I ask is, how do I shorten this? I'm new to J and so do not have enough experience to shorten it any further.

Also, if anyone has a solution shorter than this in another language, I'd be interested to see that as well!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Project Euler problem 1 \$\endgroup\$
    – HamZa
    May 16, 2013 at 23:15
  • 3
    \$\begingroup\$ 6 bytes: 233168 \$\endgroup\$
    – 12Me21
    May 21, 2018 at 19:59

3 Answers 3

8
\$\begingroup\$

Employing a few forks, a hook and the fact that J works well on lists:

+/(#~[:+./0=3 5|/])i.1000

This answer uses your algorithm, but just uses some J tricks to make it a bit shorter. I'm fairly sure that this can be made shorter still, and I wouldn't be surprised if there's a slightly different way of doing it that results in an even shorter solution.

Here's a list of some things I've done here.

First, I've combined the 3|x and the 5|x into one operation 3 5|/x. This uses the table adverb / to do both operations at once:

   3 5|/i.20
0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1
0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4

Next, I've combined the |/, the 0=, the +., and the # into a train of verbs using forks and a hook. The verb train breaks down into groups of three:

3 5|/]

this is the same as the above, except I'm using ] to grab the list to the right of the brackets.

0=x

x is the result of the previous fork which is fed into the next.

[:+./x

as before the result so far gets fed into this fork. [: tells the verb +./ that it should use its monadic (one argument) form. The / inserts the +. between the top and bottom rows of the result so far.

#~x

This is the hook. The result so far is fed in as the right argument, but the left argument is the value outside the brackets (i.1000) again. So this is equivalent to (i.1000)#~x. The ~ just reverses the order of the arguments.

Then at the end I just use the +/ as you did.

\$\endgroup\$
3
  • \$\begingroup\$ Is there anyway you could add a small explanation to what/how you're doing it? \$\endgroup\$
    – Cisplatin
    May 16, 2013 at 0:08
  • 1
    \$\begingroup\$ Yep, just working on that now. :-) \$\endgroup\$
    – Gareth
    May 16, 2013 at 0:09
  • 1
    \$\begingroup\$ +/(#~0=[:*/3 5|/])i.1e3 is two chars shorter. Basically changing OR with multiplication and shortening the number 1000. \$\endgroup\$
    – randomra
    May 16, 2013 at 11:14
4
\$\begingroup\$

Using a slightly different method than my other answer:

+/+/((]*[>])3 5*/i.)1000

Here, I'm multiplying 3 and 5 by all the numbers up to 1000, throwing away anything that's not less than 1000 and then summing them. It's a shame about the ugly +/+/ at the end.

Here we have a fork:

3 5*/i.

followed by a hook:

(]*[>])x

EDIT:

As randomra points out, I forgot about duplicates. This should fix that:

+/~.,((]*>)3 5*/i.)1000

I've also realised that [>] is the same as > (not the first time I've had that redundancy in my answer)

\$\endgroup\$
4
  • 2
    \$\begingroup\$ You double count numbers divisible by 15. \$\endgroup\$
    – randomra
    May 16, 2013 at 11:19
  • \$\begingroup\$ Ooh, never considered that. \$\endgroup\$
    – Gareth
    May 16, 2013 at 11:30
  • \$\begingroup\$ your first "+/" just removes shape - can use monadic ; instead double count can be fixed with "nub" ~. your approach is good and leads to 22 bytes +/~.;((]*>)3 5*/i.)1e3 \$\endgroup\$
    – jayprich
    May 21, 2018 at 19:47
  • \$\begingroup\$ @jayprich my shortest version is 23 bytes at the end of the answer. It's pretty much what you've got without the 1e3 for the 1000. \$\endgroup\$
    – Gareth
    May 21, 2018 at 22:02
1
\$\begingroup\$

a couple of swerves on the above to shave some bytes off

correct result 233168

  • 25 bytes +/x#(0=3|x)+.0=5|x=:i.1e3
  • 24 bytes +/(#~[:+./0=3 5|/])i.1e3
  • 22 bytes +/~.;((]*>)3 5*/i.)1e3

J, testing HCF 21 bytes

+/(*1&<@(15&+.))i.1e3

TIO

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.