问题
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.
回答1:
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.)
回答2:
- 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
来源:https://stackoverflow.com/questions/1555807/how-to-refactor-this-in-j