# Where Statement

Is there a "parallel" way to perform these operations?

Indices = {}
For[i = 1, i <= Length[w], i++,
If[w[[i]] < 0, AppendTo[Indices, i]]]


Which gives a list of the Indices where the list w is negative. This is a little slow.

Is there a faster cleaner way to get the same answer? This is essentially the Fortran 90 where statement.

-
indices = Select[w, Negative] -- not parallel, but reasonably efficient. Or Pick[w, Negative[w]]. – Michael E2 Mar 14 '14 at 15:54
If you need the indices, not the elements, use Position[w, _?Negative]. Parallelization is not the best or fastest approach for this task in Mathematica. – Szabolcs Mar 14 '14 at 16:25
Thanks Szabolcs. "Position" is what I needed. I was using "parallel" loosely, as in what was once upon a time called "SIMD" (single instructions multiple data). – JEP Mar 14 '14 at 17:06
@JEP In that case, for good performance, you can try Pick[Range@Length[w], UnitStep[w], 0]. I think this will be the fastest way to get the indices (but depending what you want to do afterwards, using the indices may not be the fastest solution). – Szabolcs Mar 14 '14 at 22:52

I suppose it's better to make my comment into an answer, per SE policy. The slowness is due to AppendTo, which has been pointed out by many others before, as well as in the documentation.

To get the indices,

indices = Pick[Range[Length[w]], UnitStep[w]]


will be fast.

Reasons for starting variable names with a lower-case letter instead of a capital have been discussed before, too.

[I misread what was being stored. Oops.]

Two possibilities:

indices = Select[w, Negative]

indices = Pick[w, Negative[w]]


Pick will be faster on large packed arrays. Or as Szabolcs points out, it will be even faster if both arguments are packed:

indices = Pick[w, UnitStep[w]]

-
Actually Pick will be fastest if both arguments are packed, i.e. Pick[w, UnitStep[w], 0]. – Szabolcs Mar 14 '14 at 16:27
Thanks to both. – JEP Mar 14 '14 at 16:37

Just for comparison: Consider following approaches:

f[x_] := Cases[x, _?Negative];
g[x_] := Select[x, Negative];
h[x_] := Pick[x, UnitStep[x], 0];
k[x_?Negative] := x;
k[x_] := Sequence[];


Testing on:

list = RandomReal[{-1, 1}, 10^6];


yields:

-

Based on @Szabolcs, we could parallelize by partitioning the list and using ParallelMap. Assuming $KernelCount is not zero, Data: w = RandomReal[{-1, 1}, Prime[10^6]];  Without parallelizing: First@Timing[a1 = Flatten@Position[w, _?Negative];]  17.097710 Parallelizing: First@Timing[ a2 = With[ { n = Quotient[Length[w],$KernelCount]
},
Flatten[
Range[0, Length[w], n]
+ ParallelMap[Flatten[Position[#, _?Negative]] &,
Partition[w, n, n, 1, {}]]
]
];]


7.441248

a1 == a2


True

-