Comment vérifier si tous les éléments suivants sont dans une liste?


115

J'ai trouvé, qu'il y a une question connexe, sur la façon de trouver si au moins un élément existe dans une liste:
Comment vérifier si l'un des éléments suivants est dans une liste?

Mais quelle est la meilleure façon pythonique de savoir si tous les éléments existent dans une liste?

En recherchant dans les documents, j'ai trouvé cette solution:

>>> l = ['a', 'b', 'c']
>>> set(['a', 'b']) <= set(l)
True
>>> set(['a', 'x']) <= set(l)
False

Une autre solution serait la suivante:

>>> l = ['a', 'b', 'c']
>>> all(x in l for x in ['a', 'b'])
True
>>> all(x in l for x in ['a', 'x'])
False

Mais ici, vous devez faire plus de frappe.

Y a-t-il d'autres solutions?


5
Quel est le problème avec set(smaller) <= set(larger)?
eumiro

1
Je pense que vos secondes solutions avec «tout» me semblent très bien et pythoniques.
Jiho Noh

Réponses:


158

Les opérateurs comme <=dans Python ne sont généralement pas surchargés pour signifier quelque chose de significativement différent de "inférieur ou égal à". C'est inhabituel que la bibliothèque standard fasse cela - cela sent comme l'ancienne API.

Utilisez l'équivalent et méthode plus clairement nommé, set.issubset. Notez que vous n'avez pas besoin de convertir l'argument en un ensemble; il le fera pour vous si nécessaire.

set(['a', 'b']).issubset(['a', 'b', 'c'])

2
Je ne savais pas que vous pouviez passer la liste directement comme argument à issubset ... sympa!
tsimbalar

1
Bien que je sois d'accord avec le sentiment, je suis plutôt d'accord avec l'idée <=et la issubsetsignification de la même chose. Pourquoi tu n'aimes pas ça?
Kirk Strauser

2
@ Just: Principalement, parce que ce n'est pas évident de savoir ce que <=signifie un ensemble sans le chercher dans la documentation ou sans avoir une connaissance préalable de ce que cela signifie en théorie des ensembles, alors que tout le monde sait ce que issubsetsignifie automatiquement.
Glenn Maynard

2
Vous connaissez l'opérateur mathématique du sous-ensemble (non approprié)? il ressemble essentiellement à un arrondi <=;)
dom0

J'adore cette solution. existe-t-il un moyen d'obtenir un emplacement d'index ou une valeur de liste au lieu d'un booléen (True: False)?
Vlad Gulin

62

J'utiliserais probablement setde la manière suivante:

set(l).issuperset(set(['a','b'])) 

ou l'inverse:

set(['a','b']).issubset(set(l)) 

Je le trouve un peu plus lisible, mais c'est peut-être excessif. Les ensembles sont particulièrement utiles pour calculer l'union / l'intersection / les différences entre les collections, mais ce n'est peut-être pas la meilleure option dans cette situation ...


En fait, MySet.issubset(MyOtherSet)et MySet <= MyOtherSetsont les mêmes.
Wok

1
@wok: oh je ne le savais pas, mais je pense que la syntaxe <= est un peu déroutante car une syntaxe similaire peut être utilisée avec des listes, mais avec une signification très différente.
tsimbalar

3
ce n'est pas vraiment déroutant si vous vous souvenez que l'inclusion définit un ordre partiel sur n'importe quel ensemble d'ensembles. C'est en fait un peu déroutant qui <=a le sens qu'il a pour les séquences: on pourrait s'attendre à ce que cela signifie «est une sous-séquence» d'ordre plutôt que lexicographique.
aaronasterling

1
@aaronasterling: mmm, personnellement, je ne pense pas trop à "l'ordre partiel" quand je tape du code :-), mais je suis d'accord sur le fait qu'utiliser <=avec des séquences me semble aussi étrange, en quelque sorte ...
tsimbalar

3
J'ai couru ici dans un petit Gotcha je voudrais mentionner: Si vous utilisez cette méthode, vous êtes en train de convertir vos listes de jeux, ce qui signifie pas de doublons. set(['a','a']).issubset(['a'])revient True.
Orangestar

11

J'aime ces deux-là car ils semblent les plus logiques, ce dernier étant plus court et probablement le plus rapide (illustré ici en utilisant setune syntaxe littérale qui a été rétroportée vers Python 2.7):

all(x in {'a', 'b', 'c'} for x in ['a', 'b'])
#   or
{'a', 'b'}.issubset({'a', 'b', 'c'})

La solution «tout» est la plus rapide lorsque vous la mesurez avec timeit (). Cela devrait être la réponse acceptée.
Attersson le

3

Et si vos listes contiennent des doublons comme celui-ci:

v1 = ['s', 'h', 'e', 'e', 'p']
v2 = ['s', 's', 'h']

Les ensembles ne contiennent pas de doublons. Ainsi, la ligne suivante renvoie True.

set(v2).issubset(v1)

Pour compter les doublons, vous pouvez utiliser le code:

v1 = sorted(v1)
v2 = sorted(v2)


def is_subseq(v2, v1):
    """Check whether v2 is a subsequence of v1."""
    it = iter(v1)
    return all(c in it for c in v2) 

Ainsi, la ligne suivante renvoie False.

is_subseq(v2, v1)

1

C'est ce que je cherchais en ligne mais malheureusement pas en ligne, mais en expérimentant sur l'interpréteur python.

>>> case  = "caseCamel"
>>> label = "Case Camel"
>>> list  = ["apple", "banana"]
>>>
>>> (case or label) in list
False
>>> list = ["apple", "caseCamel"]
>>> (case or label) in list
True
>>> (case and label) in list
False
>>> list = ["case", "caseCamel", "Case Camel"]
>>> (case and label) in list
True
>>>

et si vous avez une longue liste de variables contenues dans un sublist variable

>>>
>>> list  = ["case", "caseCamel", "Case Camel"]
>>> label = "Case Camel"
>>> case  = "caseCamel"
>>>
>>> sublist = ["unique banana", "very unique banana"]
>>>
>>> # example for if any (at least one) item contained in superset (or statement)
...
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
False
>>>
>>> sublist[0] = label
>>>
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
True
>>>
>>> # example for whether a subset (all items) contained in superset (and statement)
...
>>> # a bit of demorgan's law
...
>>> next((False for item in sublist if item not in list), True)
False
>>>
>>> sublist[1] = case
>>>
>>> next((False for item in sublist if item not in list), True)
True
>>>
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
True
>>>
>>>

0

Un exemple de la façon de procéder à l'aide d'une expression lambda serait:

issublist = lambda x, y: 0 in [_ in x for _ in y]

1
S'il vous plaît ajouter des commentaires pour expliquer / élaborer votre réponse
Sharad

0

Pas le cas d'OP, mais - pour quiconque veut affirmer une intersection dans des dictionnaires et s'est retrouvé ici en raison d'une mauvaise recherche sur Google (par exemple moi) - vous devez travailler avec dict.items:

>>> a = {'key': 'value'}
>>> b = {'key': 'value', 'extra_key': 'extra_value'}
>>> all(item in a.items() for item in b.items())
True
>>> all(item in b.items() for item in a.items())
False

C'est parce que dict.itemsrenvoie des tuples de paires clé / valeur, et tout comme n'importe quel objet en Python, ils sont comparables de manière interchangeable

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.