152 votes

Trouver l'index des éléments en fonction d'une condition en utilisant la compréhension de liste python

Le code Python suivant semble être très long lorsqu'on a l'habitude de travailler avec Matlab.

>>> a = [1, 2, 3, 1, 2, 3]
>>> [index for index,value in enumerate(a) if value > 2]
[2, 5]

Dans Matlab, je peux écrire :

>> a = [1, 2, 3, 1, 2, 3];
>> find(a>2)
ans =
     3     6

Existe-t-il une méthode abrégée pour écrire cela en Python, ou dois-je m'en tenir à la version longue ?


Merci pour toutes les suggestions et l'explication de la raison d'être de la syntaxe de Python.

Après avoir trouvé ce qui suit sur le site de numpy, je pense avoir trouvé une solution qui me convient :

http://docs.scipy.org/doc/numpy/user/basics.indexing.html#boolean-or-mask-index-arrays

En appliquant les informations de ce site web à mon problème ci-dessus, on obtiendrait les résultats suivants :

>>> from numpy import array
>>> a = array([1, 2, 3, 1, 2, 3])
>>> b = a>2 
array([False, False, True, False, False, True], dtype=bool)
>>> r = array(range(len(b)))
>>> r(b)
[2, 5]

Ce qui suit devrait alors fonctionner (mais je n'ai pas d'interpréteur Python sous la main pour le tester) :

class my_array(numpy.array):
    def find(self, b):
        r = array(range(len(b)))
        return r(b)

>>> a = my_array([1, 2, 3, 1, 2, 3])
>>> a.find(a>2)
[2, 5]

105voto

Eli Bendersky Points 82298

D'une autre manière :

>>> [i for i in range(len(a)) if a[i] > 2]
[2, 5]

D'une manière générale, il convient de rappeler que alors que find est une fonction prête à l'emploi, les compréhensions de listes sont une solution générale et donc très puissante. . Rien ne vous empêche d'écrire un find en Python et l'utiliser plus tard comme vous le souhaitez. Par exemple :

>>> def find_indices(lst, condition):
...   return [i for i, elem in enumerate(lst) if condition(elem)]
... 
>>> find_indices(a, lambda e: e > 2)
[2, 5]

Notez que j'utilise des listes ici pour imiter Matlab. Il serait plus pythonique d'utiliser des générateurs et des itérateurs.

83voto

Mike Graham Points 22480
  • En Python, vous n'utiliseriez pas du tout d'index pour cela, mais vous vous contenteriez de traiter les valeurs- [value for value in a if value > 2] . En général, le fait d'avoir affaire à des index signifie que l'on ne fait pas les choses de la meilleure façon.

  • Si vous faire ont besoin d'une API similaire à celle de Matlab, vous utiliseriez numpy numpy est un paquetage pour les tableaux multidimensionnels et les mathématiques numériques en Python, fortement inspiré de Matlab. Vous utiliserez un tableau numpy au lieu d'une liste.

     >>> import numpy
     >>> a = numpy.array([1, 2, 3, 1, 2, 3])
     >>> a
     array([1, 2, 3, 1, 2, 3])
     >>> numpy.where(a > 2)
     (array([2, 5]),)
     >>> a > 2
     array([False, False,  True, False, False,  True], dtype=bool)
     >>> a[numpy.where(a > 2)]
     array([3, 3])
     >>> a[a > 2]
     array([3, 3])

31voto

Pour moi, cela fonctionne bien :

>>> import numpy as np
>>> a = np.array([1, 2, 3, 1, 2, 3])
>>> np.where(a > 2)[0]
[2 5]

9voto

Paul McGuire Points 24790

Une autre question pourrait être : "Qu'allez-vous faire de ces indices une fois que vous les aurez obtenus ?" Si vous allez les utiliser pour créer une autre liste, alors en Python, ils sont une étape intermédiaire inutile. Si vous voulez toutes les valeurs qui correspondent à une condition donnée, utilisez simplement le filtre intégré :

matchingVals = filter(lambda x : x>2, a)

Ou rédigez votre propre liste de compréhension :

matchingVals = [x for x in a if x > 2]

Si vous voulez les retirer de la liste, la méthode Python n'est pas nécessairement de les retirer de la liste, mais d'écrire une compréhension de liste comme si vous créiez une nouvelle liste, et d'assigner à nouveau en place en utilisant la méthode listvar[:] sur le côté gauche :

a[:] = [x for x in a if x <= 2]

Fournitures Matlab find car son modèle centré sur le tableau fonctionne en sélectionnant les éléments à l'aide des indices de leur tableau. Vous avez peut Il est possible de faire cela en Python, certes, mais la façon la plus pythonique est d'utiliser des itérateurs et des générateurs, comme l'a déjà mentionné @EliBendersky.

7voto

Gerhard Hagerer Points 525

Même si la réponse est tardive : Je pense que c'est toujours une très bonne question et je pense que Python (sans bibliothèques ou outils supplémentaires comme numpy) manque toujours d'une méthode pratique pour accéder aux indices des éléments d'une liste en fonction d'un filtre défini manuellement.

Vous pouvez définir manuellement une fonction qui fournit cette fonctionnalité :

def indices(list, filtr=lambda x: bool(x)):
    return [i for i,x in enumerate(list) if filtr(x)]

print(indices([1,0,3,5,1], lambda x: x==1))

Rendement : [0, 4]

Dans mon imagination, la solution idéale consisterait à créer une classe enfant de list et à ajouter la fonction indices en tant que méthode de classe. De cette manière, seule la méthode de filtrage serait nécessaire :

class MyList(list):
    def __init__(self, *args):
        list.__init__(self, *args)
    def indices(self, filtr=lambda x: bool(x)):
        return [i for i,x in enumerate(self) if filtr(x)]

my_list = MyList([1,0,3,5,1])
my_list.indices(lambda x: x==1)

J'ai développé un peu plus ce sujet ici : http://tinyurl.com/jajrr87

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X