How to refactor this in J?

Tag: refactoring , project-euler , j , tacit-programming Author: misscool12345 Date: 2009-09-26

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.

Best Answer

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=: [email protected]@(+./)@(0 = 3 5 |"0 1 i.)

comments:

The only thing I would add to this clear answer is that |"0 1 could be written as |/ (modulus table). The table adverb / can clarify some algorithms where the core function is scalar (i.e. rank 0).

Other Answer1

  • 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