Digamos que eu tenho duas listas l1
e l2
. Eu quero executar l1 - l2
, que retorna todos os elementos de l1
não dentro l2
.
Posso pensar em uma abordagem de loop ingênuo para fazer isso, mas isso será realmente ineficiente. O que é uma maneira pitônica e eficiente de fazer isso?
Como exemplo, se eu tiver l1 = [1,2,6,8] and l2 = [2,3,5,8]
, l1 - l2
deve retornar[1,6]
Respostas:
O Python possui um recurso de linguagem chamado List Comprehensions, perfeitamente adequado para tornar esse tipo de coisa extremamente fácil. A declaração a seguir faz exatamente o que você deseja e armazena o resultado
l3
:l3
irá conter[1, 6]
.fonte
in
operador não é tão eficiente em uma lista.in
em uma lista é O (n), enquantoin
em um conjunto é O (1). No entanto, até chegar a milhares de elementos ou mais, é improvável que você note a diferença.l3 = [x for x in l1 if x not in set(l2)]
? Estou certo de queset(l2)
seria chamado mais de uma vez.l2s = set(l2)
e depois dizerl3 = [x for x in l1 if x not in l2s]
. Um pouco mais fácil.Uma maneira é usar conjuntos:
fonte
l1
, o que pode ser um efeito colateral indesejado.timeit.timeit('a = [1,2,3,4]; b = [1,3]; c = [i for i in a if a not in b]', number=100000) -> 0.12061533199999985
timeit.timeit('a = {1,2,3,4}; b = {1,3}; c = a - b', number=100000) -> 0.04106225999998969
. Então, se o desempenho é um fator significativo, esta resposta pode ser mais apropriado (e também se você não se preocupam com duplicatas ou ordem)Como alternativa, você também pode usar
filter
com a expressão lambda para obter o resultado desejado. Por exemplo:Comparação de desempenho
Aqui estou comparando o desempenho de todas as respostas mencionadas aqui. Como esperado, a
set
operação baseada em Arkku é mais rápida.Diferença de conjunto de Arkku - primeiro (0,124 usec por loop)
Compreensão da lista de Daniel Pryden com
set
pesquisa - segundo (0,302 usec por loop)Compreensão da lista de rosquinhas na lista simples - Terceira (0,552 usec por loop)
O uso de
filter
Moinuddin Quadri - Quarto (0,972 usec por loop)Akshay Hazari usando a combinação de
reduce
+filter
- Quinto (3,97 usec por loop)PS:
set
não mantém a ordem e remove os elementos duplicados da lista. Portanto, não use diferença definida se precisar de alguma dessas opções .fonte
Expandindo a resposta de Donut e as outras respostas aqui, você pode obter resultados ainda melhores usando uma compreensão de gerador em vez de uma compreensão de lista e usando uma
set
estrutura de dados (já que oin
operador é O (n) em uma lista, mas O (1) em um conjunto).Então, aqui está uma função que funcionaria para você:
O resultado será um iterável que buscará preguiçosamente a lista filtrada. Se você precisar de um objeto de lista real (por exemplo, se precisar fazer uma avaliação
len()
do resultado), poderá criar facilmente uma lista como esta:fonte
Use o tipo de conjunto Python. Isso seria o mais pitonico. :)
Além disso, como é nativo, também deve ser o método mais otimizado.
Vejo:
http://docs.python.org/library/stdtypes.html#set
http://docs.python.org/library/sets.htm (para python mais antigo)
fonte
l1
incluir elementos repetidos.use Set Comprehensions {x para x em l2} ou set (l2) para definir, depois use List Comprehensions para obter list
código de teste de referência:
resultado do teste de benchmark:
fonte
l2set = set( l2 )
em vez del2set = { x for x in l2 }
Solução alternativa:
fonte