Como verificar se todos os itens a seguir estão em uma lista?


113

Descobri, que há uma dúvida relacionada, sobre como saber se existe pelo menos um item em uma lista:
Como verificar se um dos seguintes itens está em uma lista?

Mas qual é a melhor e pítônica maneira de descobrir se todos os itens existem em uma lista?

Pesquisando nos documentos, encontrei esta solução:

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

Outra solução seria esta:

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

Mas aqui você deve digitar mais.

Existe alguma outra solução?


5
O que há de errado set(smaller) <= set(larger)?
eumiro

1
Eu acho que sua segunda solução com 'todos' parece muito boa e pítônica para mim.
Jiho Noh

Respostas:


156

Operadores como <=em Python geralmente não são substituídos para significar algo significativamente diferente do que "menor ou igual a". É incomum que a biblioteca padrão faça isso - para mim, cheira a uma API legada.

Use o método equivalente e com nome mais claro set.issubset,. Observe que você não precisa converter o argumento em um conjunto; ele fará isso por você, se necessário.

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

2
não sabia que você poderia passar a lista diretamente como um argumento para issubset ... bom!
tsimbalar

1
Embora eu concorde com o sentimento, estou bem com a ideia <=e o issubsetsignificado da mesma coisa. Por que você não gosta disso?
Kirk Strauser

2
@ Apenas: Primeiramente, porque não é óbvio o que <=significa para um conjunto sem procurar nos documentos ou ter um conhecimento prévio do que significa na teoria dos conjuntos, enquanto todos sabem o que issubsetsignifica automaticamente.
Glenn Maynard

2
Você conhece o operador matemático do subconjunto (inadequado)? basicamente se parece muito com um arredondado <=;)
dom0

amo esta solução. existe uma maneira de obter uma localização de índice ou um valor de lista em vez de um bool (True: False)?
Vlad Gulin

62

Eu provavelmente usaria set da seguinte maneira:

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

ou do outro modo :

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

Acho que é um pouco mais legível, mas pode ser exagerado. Os conjuntos são particularmente úteis para calcular a união / interseção / diferenças entre as coleções, mas pode não ser a melhor opção nesta situação ...


Na verdade, MySet.issubset(MyOtherSet)e MySet <= MyOtherSetsão iguais.
Wok

1
@wok: oh, eu não sabia disso, mas acho que a sintaxe <= é um pouco confusa, pois uma sintaxe semelhante pode ser usada com listas, mas com um significado muito diferente.
tsimbalar

3
não é tão confuso se você lembrar que a inclusão define uma ordem parcial em qualquer conjunto de conjuntos. Na verdade, é um pouco confuso <=o significado que tem para as sequências: pode-se esperar que signifique 'é uma subsequência' em vez de ordenação lexicográfica.
aaronasterling

1
@aaronasterling: mmm, eu pessoalmente não penso muito sobre "ordem parcial" quando digito o código :-), mas concordo com o fato de que usar <=com sequências também parece estranho, de alguma forma ...
tsimbalar

3
Encontrei um pequeno problema aqui que gostaria de mencionar: se você usar esse método, estará convertendo suas listas em conjuntos, o que significa que não há duplicatas. set(['a','a']).issubset(['a'])retorna True.
Orangestar

11

Gosto desses dois porque parecem os mais lógicos, sendo o último mais curto e provavelmente mais rápido (mostrado aqui usando seta sintaxe literal que foi portada para o Python 2.7):

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

A solução "tudo" é a mais rápida quando você mede com timeit (). Esta deve ser a resposta aceita.
Attersson

3

E se suas listas contiverem duplicatas como esta:

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

Os conjuntos não contêm duplicatas. Portanto, a linha a seguir retorna True.

set(v2).issubset(v1)

Para contar as duplicatas, você pode usar o código:

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) 

Portanto, a linha a seguir retorna False.

is_subseq(v2, v1)

1

Isso era o que eu estava pesquisando online, mas infelizmente não encontrei online, mas enquanto fazia experiências no interpretador 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
>>>

e se você tem uma lista looonga de variáveis ​​mantidas em um 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

Um exemplo de como fazer isso usando uma expressão lambda seria:

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

1
Por favor, adicione comentários para explicar / elaborar sua resposta
Sharad

0

Não é o caso da OP, mas - para quem quer declarar interseção em dictos e acabou aqui devido a uma busca ruim no Google (por exemplo, eu) - você precisa trabalhar com 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

Isso dict.itemsocorre porque retorna tuplas de pares de chave / valor e, assim como qualquer objeto em Python, são intercambiavelmente comparáveis

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.