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.

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

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

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)

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


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}

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}


1

Mach das einfach:

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

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.