Charles Brunet
Charles Brunet

Reputation: 23150

Finding integers divisible by x an y in J

Writing my first J program to solver Euler problem #1 (find the sum of all natural numbers below 1000 that are multiples of 3 or 5), I got the following solution:

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

However, I pretty sure there is a clever way of doing it, without using a variable. I tried to rewrite it using a fork, but I don't see how I could replace the expression between () as a verb applied to 3 5 and i.1000. Could anybody help me?

Upvotes: 0

Views: 223

Answers (1)

kaleidic
kaleidic

Reputation: 3140

To parameterize both values, and thus generalize to a dyadic verb, we'll need to pass each of the parameters through to the places where they're needed. We can focus on the sole point where 3 5 is actually needed by starting with this fork:

   3 5 ([ |/ i.@]) 1000

In the overall program we need the integers list in two places. The name (n) gave us an easy way to use that list in both places. To quickly get the whole program in place, in writing this I initially calculated the list twice:

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

This succeeds at phrasing your whole program as a dyadic verb, but there are disadvantages to having i. appear twice. We can extract it to occur only once by making it the right tine of a fork. The center of that fork is a new, inner, verb.

   3 5 ([: +/ [ (] # [:+./ 0= [ |/ ]) i.@]) 1000
NB.              ___________________             new "inner" verb, parenthesized

This inner verb needs to receive the 3 5 as an argument so I pass through the left argument of the outermost verb as the left argument to this inner verb. This means Left ([) in the inner verb has the same value it had in the previous version, when it referred to the outermost argument. Within this new verb Right (]) refers to the list of integers, occurring in the two places that i.@] appeared before.

Postscript: As you showed in your comment, [ |/ ] simplifies to |/

Upvotes: 3

Related Questions