perl PDL indexing and which

136 views Asked by At

I try find index of ndarray of PDL

pdl> p $a
[3 4 6 3 2 3 5 6 1 7]
pdl> p $aa = pdl(0,1,2,3,4,5,6,7,8,9)
[0 1 2 3 4 5 6 7 8 9]
pdl> p $b = uniq $a
[1 2 3 4 5 6 7]
pdl> p $c = $a->(*1) == $b

[
 [0 0 1 0 0 0 0]
 [0 0 0 1 0 0 0]
 [0 0 0 0 0 1 0]
 [0 0 1 0 0 0 0]
 [0 1 0 0 0 0 0]
 [0 0 1 0 0 0 0]
 [0 0 0 0 1 0 0]
 [0 0 0 0 0 1 0]
 [1 0 0 0 0 0 0]
 [0 0 0 0 0 0 1]
]

but there is no whichover, which is return whole ndarray and I want index of occur value of $a Example for 3 in $a, it occur index 0, 3, 5 so I get 0, 3, 5 of $aa

If I try rle method

pdl> p $a->qsort->rle
[1 1 3 1 1 2 1] [1 2 3 4 5 6 7]

It's return how many time, not index

If I try like this

pdl> map { print which $a == $_ } $b->list
[8][4][0 3 5][1][6][2 7][9]

I Can't figure out how store is value and $a is HUGE, so I don't think map with $b->list is good idea Any help?

2

There are 2 answers

6
Håkon Hægland On

Does the following answer your question:

use PDL;
my $a = pdl [3, 4, 6, 3, 2, 3, 5, 6, 1, 7];
my $b = pdl 3;
say $a->in($b)->which;

Output:

[0 3 5]
0
Ed. On

Here is an implementation of whichover with your data. It fills any remaining slots with -1, since that is an invalid value for this context. I have made it only support D data, but that is trivial to change.

use strict;
use warnings;
use PDL;
use Inline Pdlpp => 'DATA';

my $a = pdl q[3 4 6 3 2 3 5 6 1 7];
my $b = $a->uniq;
my $c = +($a->dummy(0) == $b)->transpose;

print $c, "\n";
print PDL::whichover($c), "\n";

__DATA__
__Pdlpp__
use PDL::Types qw(ppdefs_all);
pp_def('whichover',
  HandleBad => 1,
  Pars => 'a(n); [o]o(n)',
  GenericTypes => [ppdefs_all],
  Code => <<'EOF',
PDL_Indx last = 0, i;
loop(n) %{ if ($a()) $o(n=>last++) = n; %}
for (i = last; i < $SIZE(n); i++) $o(n=>i) = -1;
EOF
);

Output:


[
 [0 0 0 0 0 0 0 0 1 0]
 [0 0 0 0 1 0 0 0 0 0]
 [1 0 0 1 0 1 0 0 0 0]
 [0 1 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 1 0 0 0]
 [0 0 1 0 0 0 0 1 0 0]
 [0 0 0 0 0 0 0 0 0 1]
]


[
 [ 8 -1 -1 -1 -1 -1 -1 -1 -1 -1]
 [ 4 -1 -1 -1 -1 -1 -1 -1 -1 -1]
 [ 0  3  5 -1 -1 -1 -1 -1 -1 -1]
 [ 1 -1 -1 -1 -1 -1 -1 -1 -1 -1]
 [ 6 -1 -1 -1 -1 -1 -1 -1 -1 -1]
 [ 2  7 -1 -1 -1 -1 -1 -1 -1 -1]
 [ 9 -1 -1 -1 -1 -1 -1 -1 -1 -1]
]

For an extra flourish you could setvaltobad with -1, and use a slice with ngoodover->max to chop the 2D shape to its narrowest width. For a further flourish that might help your application, you could also append the 2D shape to the transpose of $b so you have each value in 0th column followed by the indices where it occurs followed by -1/BAD.

whichover will be added to PDL shortly; expect to see it in PDL 2.086. Also, Inline::Pdlpp needs to make available PDL::Types, which will also happen for PDL 2.086 - EDIT Just put use PDL::Types qw(ppdefs_all); at the start. Also also that second loop proves I need to implement loop (n=value) and then apply that in PDL::LinearAlgebra.