How to shorten this J code? (Or write shorter code in another language)

4

1

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!

Cisplatin

Posted 2013-05-15T23:48:10.777

Reputation: 403

1Project Euler problem 1 – HamZa – 2013-05-16T23:15:50.933

26 bytes: 233168 – 12Me21 – 2018-05-21T19:59:02.947

Answers

7

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.

Gareth

Posted 2013-05-15T23:48:10.777

Reputation: 11 678

Is there anyway you could add a small explanation to what/how you're doing it? – Cisplatin – 2013-05-16T00:08:31.427

1Yep, just working on that now. :-) – Gareth – 2013-05-16T00:09:08.573

1+/(#~0=[:*/3 5|/])i.1e3 is two chars shorter. Basically changing OR with multiplication and shortening the number 1000. – randomra – 2013-05-16T11:14:32.097

3

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)

Gareth

Posted 2013-05-15T23:48:10.777

Reputation: 11 678

2You double count numbers divisible by 15. – randomra – 2013-05-16T11:19:55.880

Ooh, never considered that. – Gareth – 2013-05-16T11:30:30.533

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 – jayprich – 2018-05-21T19:47:20.287

@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. – Gareth – 2018-05-21T22:02:52.187

1

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

jayprich

Posted 2013-05-15T23:48:10.777

Reputation: 391