Abrufen von Indizes für True-Werte in einer Booleschen Liste

87

Ich habe einen Teil meines Codes, in dem ich eine Telefonzentrale erstellen soll. Ich möchte eine Liste aller eingeschalteten Schalter zurückgeben. Hier ist "Ein" gleich Trueund "Aus" gleich False. Jetzt möchte ich nur eine Liste aller TrueWerte und ihrer Position zurückgeben. Dies ist alles, was ich habe, aber es gibt nur die Position des ersten Auftretens von zurück True(dies ist nur ein Teil meines Codes):

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]

Dies gibt nur "4" zurück.

Amon
quelle

Antworten:

117

Verwenden enumerate, list.indexgibt den Index der ersten gefundenen Übereinstimmung zurück.

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

Für große Listen ist es besser, Folgendes zu verwenden 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
quelle
Ahh, ich verstehe, ich habe einige ähnliche Fragen gesehen, die mir sagten, ich solle Aufzählung verwenden, aber ich glaube, ich habe es falsch verwendet. Ich habe die Liste gleich gesetzt xund dann getan, enumerate(x)aber ich denke, alles, was ich getan habe, war 4 aufzuzählen? Ist es das, was passiert ist? Vielen Dank für die Hilfe
Amon
Auch was passiert, wenn Sie i for i, xim Listenverständnis tun ? Ich bin es nur gewohnt, i for izum Beispiel oder ein ähnliches Format zu sehen, wovon funktioniert es x? Danke
Amon
1
@Amon enumerategibt während der Schleife ein Tupel (ind, value) zurück. Jetzt können wir die Elemente des Tupels zwei Variablen zuweisen, indem wir : i, x = (ind, value). Genau das passiert in dieser Schleife.
Ashwini Chaudhary
Oh, ich sehe, was jetzt passiert. Vielen Dank für Ihre Hilfe!
Amon
Ändern Sie für alle Benutzer von Python3 in der itertools.compressLösung das xrangein range. ( xrangewurde rangein Python 3 umbenannt)
MehmedB
64

Wenn Sie numpy zur Verfügung haben:

>>> 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])
jterrace
quelle
8
Beachten Sie, dass dies ein Tupel zurückgibt, das np.where(states)[0]die Ergebnisse tatsächlich verwenden muss
Rufus
17

TL; DR : Verwenden Sie, np.whereda dies die schnellste Option ist. Ihre Optionen sind np.where, itertools.compressund list comprehension.

Siehe den Vergleich unten, wo es gesehen werden kann , np.whereübertrifft sowohl itertools.compressals auchlist 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
  • Methode 1: Verwenden 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)
  • Methode 2: Verwenden itertools.compress
>>> %timeit list(compress(range(len(t)), t))
210 µs ± 704 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
  • Methode 3 (die schnellste Methode): Verwenden numpy.where
>>> %timeit np.where(t)
179 µs ± 593 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Meysam Sadeghi
quelle
2

Sie können Filter dafür verwenden:

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

Das rangehier listet Elemente Ihrer Liste auf und da wir nur diejenigen wollen, wo es self.statesist True, wenden wir einen Filter an, der auf dieser Bedingung basiert.

Für Python> 3.0:

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

Sashkello
quelle
1

Verwenden Sie Wörterbuch Verständnis Weg,

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

Eingang:

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

Ausgabe:

{4: True, 5: True, 7: True}
Anfänger
quelle
3
Es ist ein Diktatverständnis, kein Listenverständnis.
Ashwini Chaudhary
1

Verwenden der elementweisen Multiplikation und einer Menge:

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

Ausgabe: {4, 5, 7}

Nate
quelle
1

Mach das einfach:

def which_index(self):
    return [
        i for i in range(len(self.states))
        if self.states[i] == True
    ]
ArnabJyoti Thakuria
quelle
Vielen Dank für Ihren Beitrag und willkommen bei StackOverflow. Lesen Sie jedoch die Bearbeitungshilfe , um Ihre Formatierung zu verbessern, und fügen Sie Ihrem Code einige Erklärungen hinzu. Vielen Dank!
Will