سؤال

I need something like Position function for Mathematica (http://reference.wolfram.com/mathematica/ref/Position.html) but in Q. My solution for rectangular matrix is following:

q) colrow:{sz:count x; $[(count first x) = 1; enlist y; (floor y % sz;  y mod sz)]}
q) position:{flip colrow[x;(where raze x = y)]}

It works straightforward for rectangular matrices and lists:

q) t:(1 -1  1;  / matrix test
     -1  3  4; 
      1 -1  1);

q) pos1:position[t;-1]   / try to find all positions of -1
q) pos1
 0 1
 1 0
 2 1

q) t ./: pos1   / here get items
 -1 -1 -1

q) l:1 0 3 0 2 3 4 1 0  / list test
q) pos2:position[l;0]   / try to find all positions of 0

q) pos2
 1
 3
 8

q) l ./: pos2 / get items
 0 0 0 

This works but it'd be good to have more general solution for arbitrary lists and not only rectangular matrices. For instance code above won't work correctly for arguments like:

position[(1 2 3; 1 2; 1 2 1 4); 1]

May be someone has generic solution for that ?

هل كانت مفيدة؟

المحلول

How's this look? I think it should work for all two-dimensional lists, ragged or rectangular, and also for vectors. (I haven't worked out a version for arbitrary dimensions yet.)

q)position:{{$[type x;enlist each where x;raze flip each flip(til count x;raze each .z.s each x)]}x=y}
q)t
1  -1 1
-1 3  4
1  -1 1
q)l
1 0 3 0 2 3 4 1 0
q)r
1 2 3
1 2
1 2 1 4
q)pos1:position[t;-1]
q)pos2:position[l;0]
q)pos3:position[r;1]
q)pos1
0 1
1 0
2 1
q)pos2
1
3
8
q)pos3
0 0
1 0
2 0
2 2
q)t ./:pos1
-1 -1 -1
q)l ./:pos2
0 0 0
q)r ./:pos3
1 1 1 1
q)

EDIT:

Here's a version that works for all dimensions except 1 (and 0 of course):

q)position2:{{$[type x;where x;raze each raze flip each flip(til count x;.z.s each x)]}x=y}
q)r2:(r;r)
q)0N!r2;
((1 2 3;1 2;1 2 1 4);(1 2 3;1 2;1 2 1 4))
q)pos4:position2[r2;1]
q)0N!pos4;
(0 0 0;0 1 0;0 2 0;0 2 2;1 0 0;1 1 0;1 2 0;1 2 2)
q)r2 ./:pos4
1 1 1 1 1 1 1 1
q)r ./:position2[r;1]
1 1 1 1
q)t ./:position2[t;-1]
-1 -1 -1
q)

On vectors, though, it returns an address vector, not an address matrix, so it has to be used with @, not .:

q)0N!position2[l;0];
1 3 8
q)l ./:position2[l;0]
'type
q)l position2[l;0]
0 0 0
q)

If you really need it to work the same way on vectors as on higher-dimensional structures, the simplest solution is probably just to special-case them directly:

q)position3:{$[type x;enlist each where@;{$[type x;where x;raze each raze flip each flip(til count x;.z.s each x)]}]x=y}
q)position3[l;0]
1
3
8
q)l ./:position3[l;0]
0 0 0
q)r2 ./:position3[r2;1]
1 1 1 1 1 1 1 1
q)r ./:position3[r;1]
1 1 1 1
q)t ./:position3[t;-1]
-1 -1 -1
q)

نصائح أخرى

Below should also work.
Not the exact solution but workable.

pos:{$[type x;where x=y;where each x=y]}  
val:{raze ($[0h=type x;x@';x@])pos[x;y]}  
q)t:(1 -1  1;-1 3 4;1 -1 1)  
q)pos[t;-1]  
1  
0  
1  
q)val[t;-1]  
-1  
-1  
-1  
q)l:1 0 3 0 2 3 4 1 0  
q)pos[l;0]  
1 3 8  
q)val[l;0]  
0 0 0  
q)r:(1 2 3; 1 2; 1 2 1 4)  
q)pos[r;1]  
,0
,0
0 2
q)val[r;1]  
1 1 1 1  
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top