Obtenir des indices de valeurs True dans une liste booléenne


87

J'ai un morceau de mon code où je suis censé créer un standard. Je souhaite renvoyer une liste de tous les commutateurs activés. Ici, "on" sera égal Trueet "off" égal False. Alors maintenant, je veux juste renvoyer une liste de toutes les Truevaleurs et leur position. C'est tout ce que j'ai mais cela ne renvoie que la position de la première occurrence de True(ce n'est qu'une partie de mon code):

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]

Cela ne renvoie que "4"

Réponses:


115

Utiliser enumerate, list.indexrenvoie l'index de la première correspondance trouvée.

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

Pour les listes volumineuses, il vaut mieux utiliser 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 je vois, j'ai vu des questions similaires me disant d'utiliser enumerate, mais je suppose que je l'utilisais mal. Je définissais la liste égale à x, puis faisais enumerate(x)mais je suppose que tout ce que je faisais était d'énumérer 4? C'est ce qui se passait? Merci pour l'aide
Charles Smith

Que se passe-t-il également lorsque vous faites i for i, xla compréhension de la liste? Je n'ai l'habitude de voir que i for ipar exemple, ou un format similaire, quelle est la fonction de x? Merci
Charles Smith

1
@Amon enumerateretourne un tuples (ind, valeur) au cours de la boucle, nous pouvons maintenant affecter les éléments du tuple à deux variables à l' aide: i, x = (ind, value). C'est exactement ce qui se passe dans cette boucle.
Ashwini Chaudhary

Oh je vois ce qui se passe maintenant. Merci beaucoup pour votre aide!
Charles Smith

Pour toute personne utilisant Python3, dans la itertools.compresssolution, remplacez le fichier xrangepar range. (a xrangeété renommé rangeen Python 3.)
MehmedB

64

Si vous avez 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
Notez que cela renvoie un tuple qui nécessite np.where(states)[0]d'utiliser réellement les résultats
Rufus

17

TL; DR : à utiliser np.wherecar c'est l'option la plus rapide. Vos options sont np.where, itertools.compressetlist comprehension .

Voir la comparaison détaillée ci-dessous, où il peut être vu np.wheresurpasse à la fois itertools.compresset aussilist 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éthode 1: Utilisation 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éthode 2: utilisation 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éthode 3 (la méthode la plus rapide): Utilisation numpy.where
>>> %timeit np.where(t)
179 µs ± 593 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

2

Vous pouvez utiliser un filtre pour cela:

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

L' rangeici énumère les éléments de votre liste et comme nous ne voulons que ceux où self.statesest True, nous appliquons un filtre basé sur cette condition.

Pour Python> 3.0:

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


1

Utilisez la manière de comprendre le dictionnaire,

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

Contribution:

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

Production:

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

3
C'est une compréhension de dict, pas une compréhension de liste.
Ashwini Chaudhary

1

En utilisant la multiplication par élément et un ensemble:

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

Production: {4, 5, 7}


1

Faites simplement ceci:

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

Merci pour votre contribution et bienvenue sur StackOverflow. Cependant, veuillez lire l' aide à l' édition pour améliorer votre mise en forme et ajouter également des explications à votre code. Merci!
Sera
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.