73 votes

Utiliser la méthode list index() de Python sur une liste de tuples ou d'objets ?

Le type liste de Python possède une méthode index() qui prend un paramètre et renvoie l'indice du premier élément de la liste correspondant au paramètre. Par exemple :

>>> some_list = ["apple", "pear", "banana", "grape"]
>>> some_list.index("pear")
1
>>> some_list.index("grape")
3

Existe-t-il une manière gracieuse (idiomatique) d'étendre cela aux listes d'objets complexes, comme les tuples ? Idéalement, j'aimerais pouvoir faire quelque chose comme ceci :

>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> some_list.getIndexOfTuple(1, 7)
1
>>> some_list.getIndexOfTuple(0, "kumquat")
2

getIndexOfTuple() est juste une méthode hypothétique qui accepte un sous-index et une valeur, puis renvoie l'index de l'élément de la liste avec la valeur donnée à ce sous-index. J'espère

Existe-t-il un moyen d'obtenir ce résultat général, en utilisant des compréhensions de listes ou des lambas ou quelque chose de "en ligne" comme ça ? Je pense que je pourrais écrire ma propre classe et méthode, mais je ne veux pas réinventer la roue si Python a déjà un moyen de le faire.

84voto

Paolo Bergantino Points 199336

Que pensez-vous de ça ?

>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> [x for x, y in enumerate(tuple_list) if y[1] == 7]
[1]
>>> [x for x, y in enumerate(tuple_list) if y[0] == 'kumquat']
[2]

Comme indiqué dans les commentaires, cela permettrait d'obtenir toutes les correspondances. Pour n'obtenir que la première, vous pouvez le faire :

>>> [y[0] for y in tuple_list].index('kumquat')
2

Il y a une bonne discussion dans les commentaires quant à la différence de vitesse entre toutes les solutions postées. Je suis peut-être un peu partial, mais je m'en tiendrais personnellement à une ligne unique, car la vitesse dont nous parlons est plutôt insignifiante par rapport à la création de fonctions et à l'importation de modules pour ce problème, mais si vous avez l'intention de faire cela pour une très grande quantité d'éléments, vous pourriez vouloir regarder les autres réponses fournies, car elles sont plus rapides que ce que j'ai fourni.

31voto

Triptych Points 70247

Ces compréhensions de listes sont désordonnées au bout d'un moment.

J'aime cette approche pythique :

from operator import itemgetter

def collect(l, index):
   return map(itemgetter(index), l)

# And now you can write this:
collect(tuple_list,0).index("cherry")   # = 1
collect(tuple_list,1).index("3")        # = 2

Si vous avez besoin que votre code soit super performant :

# Stops iterating through the list as soon as it finds the value
def getIndexOfTuple(l, index, value):
    for pos,t in enumerate(l):
        if t[index] == value:
            return pos

    # Matches behavior of list.index
    raise ValueError("list.index(x): x not in list")

getIndexOfTuple(tuple_list, 0, "cherry")   # = 1

11voto

Jarret Hardie Points 36266

Une possibilité est d'utiliser le itemgetter de la fonction operator module :

import operator

f = operator.itemgetter(0)
print map(f, tuple_list).index("cherry") # yields 1

L'appel à itemgetter renvoie une fonction qui fera l'équivalent de foo[0] pour tout ce qui lui est passé. Utilisation de map vous appliquez ensuite cette fonction à chaque tuple, en extrayant les informations dans une nouvelle liste, sur laquelle vous appelez alors index comme d'habitude.

map(f, tuple_list)

est équivalent à :

[f(tuple_list[0]), f(tuple_list[1]), ...etc]

qui à son tour est équivalent à :

[tuple_list[0][0], tuple_list[1][0], tuple_list[2][0]]

ce qui donne :

["pineapple", "cherry", ...etc]

10voto

Alasdair Points 36535

Vous pouvez le faire avec une compréhension de liste et index()

tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
[x[0] for x in tuple_list].index("kumquat")
2
[x[1] for x in tuple_list].index(7)
1

2voto

Nisan.H Points 1605

Je placerais bien ceci en commentaire de Triptych, mais je ne peux pas encore commenter en raison du manque d'évaluation :

Utilisation de la méthode des énumérateurs pour faire correspondre des sous-indices dans une liste de tuples. Par exemple

li = [(1,2,3,4), (11,22,33,44), (111,222,333,444), ('a','b','c','d'),
        ('aa','bb','cc','dd'), ('aaa','bbb','ccc','ddd')]

# want pos of item having [22,44] in positions 1 and 3:

def getIndexOfTupleWithIndices(li, indices, vals):

    # if index is a tuple of subindices to match against:
    for pos,k in enumerate(li):
        match = True
        for i in indices:
            if k[i] != vals[i]:
                match = False
                break;
        if (match):
            return pos

    # Matches behavior of list.index
    raise ValueError("list.index(x): x not in list")

idx = [1,3]
vals = [22,44]
print getIndexOfTupleWithIndices(li,idx,vals)    # = 1
idx = [0,1]
vals = ['a','b']
print getIndexOfTupleWithIndices(li,idx,vals)    # = 3
idx = [2,1]
vals = ['cc','bb']
print getIndexOfTupleWithIndices(li,idx,vals)    # = 4

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