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"

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

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

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)

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


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}

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}


1

Simplemente haz esto:

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

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.