web-dev-qa-db-fra.com

Le meilleur moyen de gérer list.index (pourrait ne pas exister) en python?

J'ai un code qui ressemble à ceci:

thing_index = thing_list.index(thing)
otherfunction(thing_list, thing_index)

ok donc c'est simplifié mais vous avez l'idée. Maintenant, thing pourrait ne pas être réellement dans la liste, auquel cas je veux passer -1 en tant que thing_index. Dans d’autres langues, c’est ce à quoi vous vous attendriez à ce que index() revienne s’il ne trouvait pas l’élément. En fait, il jette une ValueError.

Je pourrais faire ça:

try:
    thing_index = thing_list.index(thing)
except ValueError:
    thing_index = -1
otherfunction(thing_list, thing_index)

Mais cela semble sale, et je ne sais pas si ValueError pourrait être élevé pour une autre raison. Je suis venu avec la solution suivante basée sur les fonctions du générateur, mais cela semble un peu complexe:

thing_index = ( [(i for i in xrange(len(thing_list)) if thing_list[i]==thing)] or [-1] )[0]

Y at-il un moyen plus propre de réaliser la même chose? Supposons que la liste n'est pas triée.

79
Draemon

Il n'y a rien de "sale" à propos de l'utilisation de la clause try-except. C'est la manière pythonique. ValueError sera généré uniquement par la méthode .index, car c'est le seul code que vous avez là!

Pour répondre au commentaire:
En Python, il est plus facile de demander pardon que d'obtenir une permission philosophie est bien établie et noindex ne soulèvera ce type d'erreur pour aucun autre problème. Pas que je puisse penser à aucun. 

52
SilentGhost
thing_index = thing_list.index(elem) if elem in thing_list else -1

Une ligne. Simple. Aucune exception.

38
Emil Ivanov

Le type dict a la fonction get , où, si la clé n'existe pas dans le dictionnaire, le deuxième argument de get est la valeur qu'il doit renvoyer. De même, il existe setdefault , qui renvoie la valeur dans dict si la clé existe, sinon il définit la valeur en fonction de votre paramètre par défaut, puis renvoie votre paramètre par défaut.

Vous pouvez étendre le type list pour avoir une méthode getindexdefault.

class SuperDuperList(list):
    def getindexdefault(self, elem, default):
        try:
            thing_index = self.index(elem)
            return thing_index
        except ValueError:
            return default

Ce qui pourrait alors être utilisé comme:

mylist = SuperDuperList([0,1,2])
index = mylist.getindexdefault( 'asdf', -1 )
15
Ross Rogers

Il n'y a rien de mal avec votre code qui utilise ValueError. Voici encore un one-line si vous souhaitez éviter les exceptions:

thing_index = next((i for i, x in enumerate(thing_list) if x == thing), -1)
5
jfs

Ce numéro est une question de philosophie linguistique. En Java, par exemple, il a toujours existé une tradition voulant que les exceptions ne soient réellement utilisées que dans des "circonstances exceptionnelles", c'est-à-dire lorsque des erreurs se sont produites, plutôt que pour flow control . Au début, c'était pour des raisons de performances car les exceptions Java étaient lentes mais c'est maintenant devenu le style accepté.

En revanche, Python a toujours utilisé des exceptions pour indiquer le déroulement normal du programme, comme en élevant une ValueError comme nous en discutons ici. Cela n’a rien de "sale" dans le style Python et il y en a beaucoup plus d’où cela vient. Un exemple encore plus courant est StopIteration exception qui est déclenché par la méthode next() d’un itérateur pour signaler qu’il n’y a plus de valeur.

3
Tendayi Mawushe

Et ça:

otherfunction(thing_collection, thing)

Plutôt que d'exposer quelque chose d'aussi dépendant de l'implémentation, comme un index de liste dans une interface de fonction, transmettez la collection et l'élément, et laissez l'autre fonction fonctionner avec les problèmes de "test d'appartenance". Si une autre fonction est écrite pour être collection-type-agnostic, alors elle commencerait probablement par:

if thing in thing_collection:
    ... proceed with operation on thing

ce qui fonctionnera si thing_collection est une liste, un tuplet, un ensemble ou un dict.

Ceci est peut-être plus clair que:

if thing_index != MAGIC_VALUE_INDICATING_NOT_A_MEMBER:

qui est le code que vous avez déjà dans une autre fonction.

1
PaulMcG

Si vous le faites souvent, il est préférable de le cuire dans une fonction d'assistance:

def index_of(val, in_list):
    try:
        return in_list.index(val)
    except ValueError:
        return -1 
0
Veneet Reddy

J'ai le même problème avec la méthode ".index ()" sur les listes. Je n'ai aucun problème avec le fait qu'il jette une exception, mais je suis fortement en désaccord avec le fait que c'est une ValueError non descriptive. Je pourrais comprendre si cela aurait été un IndexError, cependant.

Je peux comprendre pourquoi renvoyer "-1" serait également un problème, car il s'agit d'un index valide en Python. Mais de manière réaliste, je jamais n’attends une méthode ".index ()" pour renvoyer un nombre négatif.

Voici un one-liner (ok, c'est une ligne plutôt longue ...), parcourt la liste une seule fois et renvoie "Aucun" si l'élément n'est pas trouvé. Il serait trivial de le réécrire pour qu'il retourne -1, si vous le souhaitez.

indexOf = lambda list, thing: \
            reduce(lambda acc, (idx, elem): \
                   idx if (acc is None) and elem == thing else acc, list, None)

Comment utiliser:

>>> indexOf([1,2,3], 4)
>>>
>>> indexOf([1,2,3], 1)
0
>>>
0
haavee

Qu'en est-il comme ceci:

temp_inx = (L + [x]).index(x) 
inx = temp_inx if temp_inx < len(L) else -1
0
Jie Xiong

Et ça ???? :

li = [1,2,3,4,5] # create list 

li = dict(Zip(li,range(len(li)))) # convert List To Dict 
print( li ) # {1: 0, 2: 1, 3: 2, 4:3 , 5: 4}
li.get(20) # None 
li.get(1)  # 0 
0
Alaa Akiel