Obtener índices de valores verdaderos en una lista booleana

87

Tengo una parte de mi código donde se supone que debo crear una centralita. Quiero devolver una lista de todos los interruptores que están encendidos. Aquí "on" será igual Truey "off" igual False. Así que ahora solo quiero devolver una lista de todos los Truevalores y su posición. Esto es todo lo que tengo, pero solo devuelve la posición de la primera aparición de True(esto es solo una parte de mi código):

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]

Esto solo devuelve "4"

Charles Smith
fuente

Respuestas:

115

Use enumerate, list.indexdevuelve el índice de la primera coincidencia encontrada.

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

Para listas grandes, sería mejor usar 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
Ashwini Chaudhary
fuente
Ahh ya veo, vi algunas preguntas similares que me decían que usara enumerate, pero supongo que lo estaba usando mal. Estaba estableciendo la lista igual a x, luego lo enumerate(x)hice, pero supongo que todo lo que estaba haciendo era enumerar 4. ¿Eso es lo que estaba pasando? Gracias por la ayuda
Charles Smith
Además, ¿qué sucede cuando lo hace i for i, xen la lista de comprensión? Solo estoy acostumbrado a ver, i for ipor ejemplo, o un formato similar, ¿cuál es la función de x? Gracias
Charles Smith
1
@Amon enumeratedevuelve un tuplas (ind, valor) durante el bucle, ahora podemos asignar los elementos de la tupla de dos variables utilizando: i, x = (ind, value). Esto es exactamente lo que está sucediendo en ese bucle.
Ashwini Chaudhary
Oh, veo lo que está pasando ahora. ¡Muchas gracias por tu ayuda!
Charles Smith
Para cualquiera que use Python3, en la itertools.compresssolución, cambie xrangea range. ( xrangepasó a llamarse rangeen Python 3.)
MehmedB
64

Si tienes numpy disponible:

>>> 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])
terraza
fuente
8
Tenga en cuenta que esto devuelve una tupla que requiere np.where(states)[0]usar realmente los resultados
Rufus
17

TL; DR : utilícelo np.whereya que es la opción más rápida. Las opciones son np.where, itertools.compressy list comprehension.

Vea la comparación detallada a continuación, donde se puede ver que np.wheresupera a ambos itertools.compressy tambiénlist 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
  • Método 1: usar 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)
  • Método 2: usar itertools.compress
>>> %timeit list(compress(range(len(t)), t))
210 µs ± 704 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
  • Método 3 (el método más rápido): usando numpy.where
>>> %timeit np.where(t)
179 µs ± 593 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Meysam Sadeghi
fuente
2

Puede usar el filtro para ello:

filter(lambda x: self.states[x], range(len(self.states)))

El rangeaquí enumera los elementos de la lista y ya que queremos solamente aquellos en los que self.statesestá True, estamos aplicando un filtro basado en esta condición.

Para Python> 3.0:

list(filter(lambda x: self.states[x], range(len(self.states))))

sashkello
fuente
1

Utilice la forma de comprensión del diccionario,

x = {k:v for k,v in enumerate(states) if v == True}

Entrada:

states = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]

Salida:

{4: True, 5: True, 7: True}
Principiante
fuente
3
Es una comprensión de dictado, no una comprensión de listas.
Ashwini Chaudhary
1

Usando la multiplicación por elementos y un conjunto:

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

Salida: {4, 5, 7}

Nate
fuente
1

Simplemente haz esto:

def which_index(self):
    return [
        i for i in range(len(self.states))
        if self.states[i] == True
    ]
ArnabJyoti Thakuria
fuente
Gracias por su contribución y bienvenido a StackOverflow. Sin embargo, lea Ayuda de edición para mejorar su formato y también agregue alguna explicación a su código. ¡Gracias!
Será el