3
$\begingroup$

I would like to be able to extract elements from a list where indices are specified by a binary mask.

To provide an example, I would like to have a function BinaryIndex doing the following:

foo = {a, b, c}
mask = {True, False, True}
BinaryIndex[mask, foo]
(* expected output *) {a, c}

Is there such a function built-in? I would be able to come up with some implementation, but I would like to have this performance-optimized. If there is no such built-in function, what would be a good approach to make this fast?

$\endgroup$
7
$\begingroup$

Try

Pick[foo, mask]
(* {a, c}*)
$\endgroup$
3
$\begingroup$

Since this question is about performance, I'd like to add that often it's better to work with lists of integers than lists of booleans since lists of integers can be packed. For example, if you want to pick the positive elements from an array using Pick, you can either use Positive to make a boolean selector list or UnitStep to make an integer selector list:

list = RandomReal[{-1, 1}, 100000];
With[{sel = Positive[list]}, Pick[list, sel]; // RepeatedTiming]
With[{sel = UnitStep[list]}, Pick[list, sel, 1]; // RepeatedTiming]

{0.0065, Null}

{0.00099, Null}

As you can see, UnitStep is significantly faster in the Picking step because UnitStep[list] is a packed array:

Developer`PackedArrayQ[list] (* True *)
Developer`PackedArrayQ[Positive[list]] (* False *)
Developer`PackedArrayQ[UnitStep[list]] (* True*)
$\endgroup$
0
$\begingroup$

The problem with Booleans in Mathematica is that they cannot be stored in packed arrays, reducing the efficiency of their processing. Suppose that b is already a packed vector of integers, e.g., b = DeveloperToPackedArray[Boole[mask]]`. Then you should be able to obtain your result faster with

result = Pick[foo, b, 1];

You may also try the undocumented function Random`Private`PositionsOf which can be used to determine the actual list idx of indices of 1-entries in the array b; this may be useful if you can reuse idx multiple times.

idx = Random`Private`PositionsOf[b,1];
result = foo[[idx]];
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.