Getting indices of True values in a boolean list

PythonList

Python Problem Overview


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"

Python Solutions


Solution 1 - Python

Use enumerate, list.index returns the index of first match found.

>>> t = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]
>>> [i for i, x in enumerate(t) if x]
[4, 5, 7]

For huge lists, it'd be better to use itertools.compress:

>>> from itertools import compress
>>> list(compress(xrange(len(t)), t))
[4, 5, 7]
>>> t = t*1000
>>> %timeit [i for i, x in enumerate(t) if x]
100 loops, best of 3: 2.55 ms per loop
>>> %timeit list(compress(xrange(len(t)), t))
1000 loops, best of 3: 696 µs per loop

Solution 2 - Python

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 3 - Python

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 4 - Python

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 - Python

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 6 - Python

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 7 - Python

Simply do this:

def which_index(self):
    return [
        i for i in range(len(self.states))
        if self.states[i] == True
    ]

Solution 8 - Python

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 9 - Python

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])

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAmonView Question on Stackoverflow
Solution 1 - PythonAshwini ChaudharyView Answer on Stackoverflow
Solution 2 - PythonjterraceView Answer on Stackoverflow
Solution 3 - PythonMeysam SadeghiView Answer on Stackoverflow
Solution 4 - PythonsashkelloView Answer on Stackoverflow
Solution 5 - PythonNateView Answer on Stackoverflow
Solution 6 - PythonBeginnerView Answer on Stackoverflow
Solution 7 - PythonArnabJyoti ThakuriaView Answer on Stackoverflow
Solution 8 - PythonMuhammad YasirroniView Answer on Stackoverflow
Solution 9 - PythonKevinBuiView Answer on Stackoverflow