Pooja_Parthasarathy
Pooja_Parthasarathy

Reputation: 95

Mapping an array of booleans to an array of values and returning True instances in Python

I have a list of values:

 a = [1,2,3,4]

And a corresponding list of Booleans:

 b = [True, True, False, True]

I want to map b onto a such that I get all values in a such that their corresponding value in b is 'True'. So the answer in this instance would be [1,2,4]

The only way I can think of doing is to loop through the elements of b, get the indices that are True, and then retrieve the corresponding index in a. So something like:

 def maplist(l1, l2):
     # list1 is a list of Booleans to map onto list2
     l2_true = []
     for el in range(len(l1)):
        if l1[el] == True: 
            l2_true.append(l2[el])
     return l2_true

Is there a better way to do this?

Upvotes: 0

Views: 910

Answers (3)

Micke
Micke

Reputation: 2309

I know that the question states two lists, and doesn't mention numpy. But if you will consider using it, and given that a and b are numpy arrays, the mapping operation becomes trivial:

a[b]

I've taken the liberty of benchmarking the suggested options, using 1000x elements:

import numpy

a = [1,2,3,4] * 1000
b = [True, True, False, True] * 1000

def question_fn():
    l2_true = []
    for el in range(len(a)):
        if b[el] == True:
            l2_true.append(a[el])
    return l2_true

def suggestion_1():
    return [v for i, v in enumerate(a) if b[i]]

def suggestion_2():
    return [x for x,y in zip(a,b) if y]

x = numpy.array(a)
y = numpy.array(b)

def using_numpy():
    return x[y]

python -m timeit -s 'import so' 'so.question_fn()'
1000 loops, best of 3: 453 usec per loop

python -m timeit -s 'import so' 'so.suggestion_1()'
10000 loops, best of 3: 203 usec per loop

python -m timeit -s 'import so' 'so.suggestion_2()'
1000 loops, best of 3: 238 usec per loop

python -m timeit -s 'import so' 'so.using_numpy()'
10000 loops, best of 3: 23 usec per loop

Please note that the numpy timing does not include converting to arrays, otherwise it would be much slower than all of the other suggested solutions. But, if using numpy arrays from the start is an option, it might a viable solution.

Upvotes: 1

kren470
kren470

Reputation: 345

Or this:

[a[i] for i in range(len(a)) if b[i]]

Upvotes: 0

Andrew Clark
Andrew Clark

Reputation: 208705

Here is a list comprehension that should do what you want:

[v for i, v in enumerate(a) if b[i]]

Another approach:

[x for x, y in zip(a, b) if y]

Upvotes: 4

Related Questions