Ottenere indici di valori True in un elenco booleano


88

Ho un pezzo del mio codice dove dovrei creare un centralino. Voglio restituire un elenco di tutti gli interruttori che sono attivi. Qui "on" sarà uguale Truee "off" uguale False. Quindi ora voglio solo restituire un elenco di tutti i Truevalori e la loro posizione. Questo è tutto ciò che ho ma restituisce solo la posizione della prima occorrenza di True(questa è solo una parte del mio codice):

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]

Restituisce solo "4"

Risposte:


118

Usa enumerate, list.indexrestituisce l'indice della prima corrispondenza trovata.

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

Per elenchi enormi, sarebbe meglio usare 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 vedo, ho visto alcune domande simili che mi dicevano di usare enumerate, ma immagino di averlo usato male. Stavo impostando l'elenco uguale a x, quindi facendo, enumerate(x)ma immagino che tutto ciò che stavo facendo fosse enumerare 4? È quello che stava succedendo? Grazie per l'aiuto
Amon

Inoltre cosa succede quando fai i for i, xnella lista di comprensione? Sono abituato solo a vedere i for iper esempio, o un formato simile, qual è la funzione di x? Grazie
Amon

1
@Amon enumeraterestituisce una tuple (ind, valore) durante il ciclo, ora siamo in grado di assegnare gli elementi della tupla di due variabili utilizzando: i, x = (ind, value). Questo è esattamente ciò che sta accadendo in quel ciclo.
Ashwini Chaudhary

Oh capisco cosa sta succedendo adesso. Grazie mille per il tuo aiuto!
Amon

Per chiunque utilizzi Python3, nella itertools.compresssoluzione, modificare il file xrangein range. (è xrangestato rinominato rangein Python 3.)
MehmedB

64

Se hai numpy disponibile:

>>> 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
Si noti che questo restituisce una tupla che richiede np.where(states)[0]di utilizzare effettivamente i risultati
Rufus

17

TL; DR : usa np.wherein quanto è l'opzione più veloce. Le opzioni disponibili sono np.where, itertools.compresse list comprehension.

Vedere il confronto dettagliato di seguito, dove si può vedere che np.wheresupera entrambi itertools.compresse anchelist 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
  • Metodo 1: utilizzo di 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)
  • Metodo 2: utilizzo di itertools.compress
>>> %timeit list(compress(range(len(t)), t))
210 µs ± 704 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
  • Metodo 3 (il metodo più veloce): utilizzando numpy.where
>>> %timeit np.where(t)
179 µs ± 593 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

2

Puoi usare il filtro per questo:

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

Il rangequi enumera gli elementi del tuo elenco e poiché vogliamo solo quelli in cui si self.statestrova True, applichiamo un filtro basato su questa condizione.

Per Python> 3.0:

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


1

Usa la comprensione del dizionario,

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

Ingresso:

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

Produzione:

{4: True, 5: True, 7: True}

3
È una comprensione dei dettami, non delle liste.
Ashwini Chaudhary

1

Usando la moltiplicazione basata sugli elementi e un insieme:

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

Produzione: {4, 5, 7}


1

Fai semplicemente questo:

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

Grazie per il tuo contributo e benvenuto in StackOverflow. Tuttavia, leggi la Guida alla modifica per migliorare la formattazione e aggiungi anche alcune spiegazioni al tuo codice. Grazie!
Il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.