> From: Alex Gian
> Sent: Sunday, 29 August 2010 00:23
> 
> Oops, before we go any further, I've stumbled on a real gotcha
> e.g.
> 
> digits 1974 123
>   1 9 7 4
>   0 1 2 3
> 
> now, when I apply (+!) to that lot, it is also applied to the leading
> zero of 0123 - which, of course, leads to a wrong result when summed.
> AAARGH!

Firstly I tend to build these up bit by bit, making sure I'm getting what I 
want as I go. I often end up with a long one-liner that does the job. If I want 
to reuse it, or publish it then I might go to the next step and break it up 
into component verbs to make it more immediately readable.

You want to finish doing digits and (+!) on each number individually before 
moving on to the next number for the reason you've shown above. As Bill 
suggested earlier, the solution is apply digits at rank 0.
   <@(10&#.inv) 1974 123
+-------+
|1 9 7 4|
|0 1 2 3|
+-------+
      <@(10&#.inv"0) 1974 123
+-------+-----+
|1 9 7 4|1 2 3|
+-------+-----+

By default (10&#.inv) will work on the whole right argument at once. You can 
check the ranks of the verb as follows:
   (10&#.inv) b. 0
_ _ _
   
You want to modify that to feed each item in the right argument to the verb 
separately -  hence the "0.

Box ( < ) as used above is nice for illustrating how this is working but you 
want to use (+!) so:
   (+!)@(10&#.inv"0) 1974 123
2 362889 5047 28
2      4    9  0

At ( @ ) causes the verb to its left to be fed the results of the verb to its 
right each time the verb to the right is "run". In other words the rank zero is 
applied to the (+!) too. We could now sum the number individually too:
   +/@(+!)@(10&#.inv"0) 1974 123
367966 15

Athough this will give the correct answers, it isn't optimal because it isn't 
necessary to sum the numbers individually, we will get the same answer if we 
wait until all the (+!)@digits"0 operations have completed and then sum the 
resulting array and J generally performs better when operating on large rather 
than small arrays. We can signal that we want to wait by using the modified 
form of At ( @: ). IOW the following is likely to be faster:
   +/@:(+!)@(10&#.inv"0) 1974 123
367966 15

Now let's add the next step - check if the resulting values equal the original 
numbers:
   (] = +/@:(+!)@(10&#.inv"0)) 1974 123
0 0

And only filter the ones that do:
   (#~ ] = +/@:(+!)@(10&#.inv"0)) 1974 123

Of course for those numbers the result is empty, but if we check all the 
numbers up to 100000 we do get one candidate:
   (#~ ] = +/@:(+!)@(10&#.inv"0)) >: i.1e5
85837

HTH
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to