Pobieranie indeksów wartości True na liście boolowskiej

87

Mam fragment mojego kodu, w którym mam utworzyć centralę. Chcę zwrócić listę wszystkich włączonych przełączników. Tutaj „włączony” będzie równy, Truea „wyłączony” równy False. Teraz chcę po prostu zwrócić listę wszystkich Truewartości i ich pozycji. To wszystko, co mam, ale zwraca tylko pozycję pierwszego wystąpienia True(to tylko część mojego kodu):

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]

Zwraca tylko „4”

Charles Smith
źródło

Odpowiedzi:

115

Użyj enumerate, list.indexzwraca indeks pierwszego znalezionego dopasowania.

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

W przypadku dużych list lepiej byłoby użyć 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
źródło
Ahh, widzę, widziałem kilka podobnych pytań, które mówiły mi, żebym użył wyliczania, ale myślę, że użyłem go źle. Ustawiałem listę równą x, a potem robiłem, enumerate(x)ale chyba wszystko, co robiłem, to wyliczanie 4? Czy to się właśnie działo? Dzięki za pomoc
Charles Smith
Co się dzieje, gdy robisz to i for i, xze zrozumieniem listy? Przywykłem tylko do oglądania i for ina przykład podobnego formatu, jaka jest funkcja x? Dzięki
Charles Smith
1
@Amon enumerateZwraca krotki (ind, value) podczas pętli, teraz możemy przypisać elementy krotki do dwóch zmiennych przy użyciu: i, x = (ind, value). To jest dokładnie to, co dzieje się w tej pętli.
Ashwini Chaudhary
Och, widzę, co się teraz dzieje. Bardzo dziękuję za pomoc!
Charles Smith
Dla osób korzystających Python3 w itertools.compressroztworze, zmienić xrangesię range. ( w Pythonie 3 xrangezmieniono nazwę na range)
MehmedB
64

Jeśli masz dostępne numpy:

>>> 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
źródło
8
Zwróć uwagę, że zwraca krotkę, która wymaga np.where(states)[0]rzeczywistego wykorzystania wyników
Rufus
17

TL; DR : użyj, np.whereponieważ jest to najszybsza opcja. Opcje są np.where, itertools.compressi list comprehension.

Zobacz szczegółowe porównanie poniżej, na którym widać, że np.whereprzewyższa zarówno itertools.compressi równieżlist 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
  • Metoda 1: Używanie 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)
  • Metoda 2: Używanie itertools.compress
>>> %timeit list(compress(range(len(t)), t))
210 µs ± 704 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
  • Metoda 3 (najszybsza metoda): przy użyciu numpy.where
>>> %timeit np.where(t)
179 µs ± 593 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Meysam Sadeghi
źródło
2

Możesz użyć do tego filtra:

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

rangeTutaj wylicza elementy listy i ponieważ chcemy tylko tych, gdzie self.statesjest True, jesteśmy stosowania filtru w oparciu o ten stan.

Dla Pythona> 3.0:

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

sashkello
źródło
1

Korzystaj ze słownika,

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

Wejście:

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

Wynik:

{4: True, 5: True, 7: True}
Początkujący
źródło
3
Jest to rozumienie ze zrozumieniem, a nie z listy.
Ashwini Chaudhary
1

Korzystanie z mnożenia elementów i zbioru:

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

Wynik: {4, 5, 7}

Nate
źródło
1

Po prostu zrób to:

def which_index(self):
    return [
        i for i in range(len(self.states))
        if self.states[i] == True
    ]
ArnabJyoti Thakuria
źródło
Dziękujemy za Twój wkład i witamy w StackOverflow. Prosimy jednak o zapoznanie się z pomocą dotyczącą edycji, aby poprawić formatowanie, a także dodać wyjaśnienia do kodu. Dzięki!
Will