web-dev-qa-db-fra.com

Vérifier si quelque chose est (non) dans une liste dans Python

J'ai une liste de tuples dans Python , et j'ai une condition où je veux prendre la branche UNIQUEMENT si le tuple n'est pas dans la liste (s'il est dans la liste, alors je ne vouloir prendre la branche if)

if curr_x -1 > 0 and (curr_x-1 , curr_y) not in myList: 

    # Do Something

Cela ne fonctionne pas vraiment pour moi cependant. Qu'est ce que j'ai mal fait?

253
Zack

Le bogue est probablement ailleurs dans votre code, car il devrait bien fonctionner:

>>> 3 not in [2, 3, 4]
False
>>> 3 not in [4, 5, 6]
True

Ou avec des tuples:

>>> (2, 3) not in [(2, 3), (5, 6), (9, 1)]
False
>>> (2, 3) not in [(2, 7), (7, 3), "hi"]
True
405
orlp

Comment vérifier si quelque chose est (non) dans une liste en Python?

La solution la moins chère et la plus lisible consiste à utiliser l'opérateur in (ou, dans votre cas particulier, not in). Comme mentionné dans la documentation,

Les opérateurs in et not in testent leur appartenance. x in s est évalué à True si x est membre de s et à False sinon. x not in s renvoie la négation de x in s.

Aditionellement,

L'opérateur not in est défini pour avoir la valeur vraie inverse de in.

y not in x est logiquement identique à not y in x.

Voici quelques exemples:

'a' in [1, 2, 3]
# False

'c' in ['a', 'b', 'c']
# True

'a' not in [1, 2, 3]
# True

'c' not in ['a', 'b', 'c']
# False

Cela fonctionne aussi avec les n-uplets, puisque les n-uplets peuvent être utilisés (en conséquence du fait qu'ils sont également immuables):

(1, 2) in [(3, 4), (1, 2)]
#  True

Si l'objet sur le RHS définit une méthode __contains__() , in l'appellera en interne, comme indiqué dans le dernier paragraphe de la section Comparaisons de la documentation.

... in et not in sont pris en charge par les types qui sont itératifs ou implémentent la méthode __contains__(). Par exemple, vous pouvez (mais ne devriez pas) faire ceci:

[3, 2, 1].__contains__(1)
# True

in court-circuite, donc si votre élément est au début de la liste, in est évalué plus rapidement:

lst = list(range(10001))
%timeit 1 in lst
%timeit 10000 in lst  # Expected to take longer time.

68.9 ns ± 0.613 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
178 µs ± 5.01 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Si vous voulez faire plus que simplement vérifier si un élément est dans une liste, il existe des options:

  • list.index peut être utilisé pour récupérer l'index d'un élément. Si cet élément n'existe pas, un ValueError est déclenché.
  • list.count peut être utilisé si vous voulez compter les occurrences.

Le problème XY: Avez-vous envisagé sets?

Posez-vous ces questions:

  • avez-vous besoin de vérifier si un élément figure plusieurs fois dans une liste?
  • Cette vérification est-elle effectuée à l'intérieur d'une boucle ou d'une fonction appelée à plusieurs reprises?
  • Les articles que vous stockez sur votre liste sont-ils lavables? OOW, pouvez-vous appeler hash sur eux?

Si vous avez répondu "oui" à ces questions, vous devriez plutôt utiliser un set. Un test d'adhésion in sur lists est de O(n) complexité temporelle. Cela signifie que python doit effectuer un balayage linéaire de votre liste, en visitant chaque élément et en le comparant à l'élément de recherche. Si vous effectuez cette opération à plusieurs reprises ou si les listes sont volumineuses, cette opération entraînera une surcharge.

Les objets set, quant à eux, hachent leurs valeurs pour le contrôle d'appartenance à temps constant. La vérification est également effectuée à l'aide de in:

1 in {1, 2, 3} 
# True

'a' not in {'a', 'b', 'c'}
# False

(1, 2) in {('a', 'c'), (1, 2)}
# True

Si vous êtes assez malheureux pour que l'élément que vous recherchez/ne cherche pas se trouve à la fin de votre liste, python aura balayé la liste jusqu'à la fin. Cela ressort clairement des horaires ci-dessous:

l = list(range(100001))
s = set(l)

%timeit 100000 in l
%timeit 100000 in s

2.58 ms ± 58.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
101 ns ± 9.53 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Pour rappel, cette option est appropriée dans la mesure où les éléments que vous stockez et que vous regardez sont lavables. Pour l’instant, il faudrait soit des types immuables, soit des objets qui implémentent __hash__.

9
cs95