Question

My newbie solution to Project Euler #1

+/((0=3|1+i.1000-1) +. (0=5|1+i.1000-1)) * (1+i.1000-1)

I know that this can be refactored, and transformed into a function, i don't know how to do it, and I would have to read all the labs to learn it.

Was it helpful?

Solution

It isn't necessary to "handle zero" because adding zero won't change the answer so you can just use i. to generate your list of numbers below 1000, for example:

   i. 10
0 1 2 3 4 5 6 7 8 9

J works best with arrays so you should be able to ask for the residue (|) of 3 and 5 at the same time, you can use rank (") to control how the arguments are fed to residue:

   3 5 |"0 1 i. 10
0 1 2 0 1 2 0 1 2 0
0 1 2 3 4 0 1 2 3 4

The |"0 1 says to feed the left argument to | an-item-at-a-time while feeding the right arguments a-line-at-a-time. Because the right argument only consists of one line, it is fed repeatedly to each of the left argument items.

Now we can do the 0= to the whole array:

   0 = 3 5 |"0 1 i. 10
1 0 0 1 0 0 1 0 0 1
1 0 0 0 0 1 0 0 0 0

Insert an OR condition between the two items (lines) of the array:

  +./ 0 = 3 5 |"0 1 i. 10
1 0 0 1 0 1 1 0 0 1

Get the index of each 1 in the list/vector:

  I. +./ 0 = 3 5 |"0 1 i. 10
0 3 5 6 9

And sum:

 +/ I. +./ 0 = 3 5 |"0 1 i. 10

23

You can make this an explicit function/verb fairly easily:

   euler1=: verb define
+/ I. +./ 0 = 3 5 |"0 1 i. y
)

Or once you get the hang of tacit J you could define:

   euler1=: +/@I.@(+./)@(0 = 3 5 |"0 1 i.)

OTHER TIPS

  • Refactor 0= (will increases the program size)

+/((3|1+i.1000-1)+.&(0=])5|1+i.1000-1)*1+i.1000-1

  • Refactor 1+i.1000-1

+/(((3|])+.&(0=[)5|])1+i.1000-1)*1+i.1000-1

  • Refactor 1+i.1000-1 again

+/(*(3|])+.&(0=[)5|])1+i.1000-1

The only thing I couldn't refactor so far is the | operator

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top