'Getting indices of True values in a boolean list
I have a piece of my code where I'm supposed to create a switchboard. I want to return a list of all the switches that are on. Here "on" will equal True and "off" equal False. So now I just want to return a list of all the True values and their position. This is all I have but it only return the position of the first occurrence of True (this is just a portion of my code):
self.states = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]
def which_switch(self):
x = [self.states.index(i) for i in self.states if i == True]
This only returns "4"
Solution 1:[1]
If you have numpy available:
>>> import numpy as np
>>> states = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]
>>> np.where(states)[0]
array([4, 5, 7])
Solution 2:[2]
TL; DR: use np.where as it is the fastest option. Your options are np.where, itertools.compress, and list comprehension.
See the detailed comparison below, where it can be seen np.where outperforms both itertools.compress and also list comprehension.
>>> from itertools import compress
>>> import numpy as np
>>> t = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]`
>>> t = 1000*t
- Method 1: Using
list comprehension
>>> %timeit [i for i, x in enumerate(t) if x]
457 µs ± 1.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
- Method 2: Using
itertools.compress
>>> %timeit list(compress(range(len(t)), t))
210 µs ± 704 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
- Method 3 (the fastest method): Using
numpy.where
>>> %timeit np.where(t)
179 µs ± 593 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Solution 3:[3]
Using element-wise multiplication and a set:
>>> states = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]
>>> set(multiply(states,range(1,len(states)+1))-1).difference({-1})
Output:
{4, 5, 7}
Solution 4:[4]
You can use filter for it:
filter(lambda x: self.states[x], range(len(self.states)))
The range here enumerates elements of your list and since we want only those where self.states is True, we are applying a filter based on this condition.
For Python > 3.0:
list(filter(lambda x: self.states[x], range(len(self.states))))
Solution 5:[5]
Use dictionary comprehension way,
x = {k:v for k,v in enumerate(states) if v == True}
Input:
states = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]
Output:
{4: True, 5: True, 7: True}
Solution 6:[6]
Simply do this:
def which_index(self):
return [
i for i in range(len(self.states))
if self.states[i] == True
]
Solution 7:[7]
I got different benchmark result compared to @meysham answer. In this test, compress seems the fastest (python 3.7).
from itertools import compress
import numpy as np
t = [True, False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]
%timeit [i for i, x in enumerate(t) if x]
%timeit list(compress(range(len(t)), t))
%timeit list(filter(lambda x: t[x], range(len(t))))
%timeit np.where(t)[0]
# 2.54 µs ± 400 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
# 2.67 µs ± 600 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
# 6.22 µs ± 624 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
# 6.52 µs ± 768 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
t = 1000*t
%timeit [i for i, x in enumerate(t) if x]
%timeit list(compress(range(len(t)), t))
%timeit list(filter(lambda x: t[x], range(len(t))))
%timeit np.where(t)[0]
# 1.68 ms ± 112 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 947 µs ± 105 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# 3.96 ms ± 97 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# 2.14 ms ± 45.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Solution 8:[8]
You can filter by using boolean mask array with square bracket, it's faster than np.where
>>> states = [True, False, False, True]
>>> np.arange(len(states))[states]
array([0, 3])
>>> size = 1_000_000
>>> states = np.arange(size) % 2 == 0
>>> states
array([ True, False, True, ..., False, True, False])
>>> true_index = np.arange(size)[states]
>>> len(true_index)
500000
>>> true_index
array([ 0, 2, 4, ..., 999994, 999996, 999998])
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Brad Solomon |
| Solution 2 | |
| Solution 3 | Nate |
| Solution 4 | Jeril |
| Solution 5 | |
| Solution 6 | Will |
| Solution 7 | Muhammad Yasirroni |
| Solution 8 | KevinBui |
