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"

Charles Smith
la source

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
Ashwini Chaudhary
la source
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])
jterrace
la source
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)
Meysam Sadeghi
la source
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))))

sashkello
la source
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}
Débutant
la source
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}

Nate
la source
1

Faites simplement ceci:

def which_index(self):
    return [
        i for i in range(len(self.states))
        if self.states[i] == True
    ]
ArnabJyoti Thakuria
la source
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