Given a key (in the sense of /.), I'd like to obtain the rank (the
i.~\:~ kind, not the " kind) of each item within the collection
corresponding to its key. My first instinct was to try (i.~\:~)/. but
this is not exactly what I want.

 

In the following example, collection 0 is 10 30 20 20 and has ranks 3 0
1 1, while collection 1 is 200 100 300 and has ranks 1 2 0. The problem
is the extra 0 appended to make them the same size, and the rearranging
that happens. I want the output to be 3 1 2 0 0 1 1, so that it
corresponds to the original right-side input.

 

   0 1 1 1 0 0 0 (i.~\:~)/. 10 200 100 300 30 20 20

3 0 1 1

1 2 0 0

 

I found that the following expression works.

 

rankbykey=: +/@( =...@[ ( [ * (i.~\:~"_1)@:( (*"_1 _))) ] )

 

For example:

 

   0 1 1 1 0 0 0 rankbykey 10 200 100 300 30 20 20

3 1 2 0 0 1 1

   (1 1,1 0,:1 0) rankbykey 0 0,0 1,:0 2

0 1 0

 

However,  rankbykey runs out of memory when I apply it to huge arrays
(15M rows, 7 cols). So then I found the following solution, which works
better on huge arrays.

 

rankbykey2=: ( ;@((i.~\:~)&.>@</.) /: ;@([</....@#@]) )

 

This seems needlessly messy because of the boxing, and I imagine others
have run into the same question, although I haven't been able to find
anything in phrases or the the wiki. It looks like something J should do
easily, but I am no J expert. Does anyone know a better solution that
will work on large arrays?

 

Thanks,

Jordan

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

Reply via email to