Pergunta

Eu tenho duas listas em Python, como estas:

temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']

Preciso criar uma terceira lista com itens da primeira lista que não estão presentes no segundo. Do exemplo que tenho que obter:

temp3 = ['Three', 'Four']

Existem maneiras rápidas sem ciclos e verificação?

Foi útil?

Solução

In [5]: list(set(temp1) - set(temp2))
Out[5]: ['Four', 'Three']

Cuidado com isso

In [5]: set([1, 2]) - set([2, 3])
Out[5]: set([1]) 

onde você pode esperar/deseja que seja igual set([1, 3]). Se você quiser set([1, 3]) Como sua resposta, você precisará usar set([1, 2]).symmetric_difference(set([2, 3])).

Outras dicas

Todas as soluções existentes oferecem uma ou outra de:

  • Desempenho mais rápido que o (n*m).
  • Preservar a lista de entrada da lista de entrada.

Mas até agora nenhuma solução tem os dois. Se você quiser os dois, tente o seguinte:

s = set(temp2)
temp3 = [x for x in temp1 if x not in s]

Teste de performance

import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print timeit.timeit('list(set(temp1) - set(temp2))', init, number = 100000)
print timeit.timeit('s = set(temp2);[x for x in temp1 if x not in s]', init, number = 100000)
print timeit.timeit('[item for item in temp1 if item not in temp2]', init, number = 100000)

Resultados:

4.34620224079 # ars' answer
4.2770634955  # This answer
30.7715615392 # matt b's answer

O método que apresentei e a preservação da ordem também é (ligeiramente) mais rápido que a subtração definida, pois não requer construção de um conjunto desnecessário. A diferença de desempenho seria mais perceptível se a primeira lista for consideravelmente maior que a segunda e se a hash for cara. Aqui está um segundo teste demonstrando o seguinte:

init = '''
temp1 = [str(i) for i in range(100000)]
temp2 = [str(i * 2) for i in range(50)]
'''

Resultados:

11.3836875916 # ars' answer
3.63890368748 # this answer (3 times faster!)
37.7445402279 # matt b's answer
temp3 = [item for item in temp1 if item not in temp2]

A diferença entre duas listas (digamos List1 e List2) pode ser encontrada usando a seguinte função simples.

def diff(list1, list2):
    c = set(list1).union(set(list2))  # or c = set(list1) | set(list2)
    d = set(list1).intersection(set(list2))  # or d = set(list1) & set(list2)
    return list(c - d)

ou

def diff(list1, list2):
    return list(set(list1).symmetric_difference(set(list2)))  # or return list(set(list1) ^ set(list2))

Usando a função acima, a diferença pode ser encontrada usando diff(temp2, temp1) ou diff(temp1, temp2). Ambos darão o resultado ['Four', 'Three']. Você não precisa se preocupar com a ordem da lista ou qual lista deve ser dada primeiro.

Referência do Doc Python

Caso você queira recursivamente a diferença, escrevi um pacote para o Python:https://github.com/seperman/deepdiff

Instalação

Instale a partir de Pypi:

pip install deepdiff

Exemplo de uso

Importação

>>> from deepdiff import DeepDiff
>>> from pprint import pprint
>>> from __future__ import print_function # In case running on Python 2

O mesmo objeto retorna vazio

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = t1
>>> print(DeepDiff(t1, t2))
{}

Tipo de item mudou

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:"2", 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{ 'type_changes': { 'root[2]': { 'newtype': <class 'str'>,
                                 'newvalue': '2',
                                 'oldtype': <class 'int'>,
                                 'oldvalue': 2}}}

O valor de um item mudou

>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:4, 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

Item adicionado e/ou removido

>>> t1 = {1:1, 2:2, 3:3, 4:4}
>>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff)
{'dic_item_added': ['root[5]', 'root[6]'],
 'dic_item_removed': ['root[4]'],
 'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}

Diferença de string

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}}
>>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { 'root[2]': {'newvalue': 4, 'oldvalue': 2},
                      "root[4]['b']": { 'newvalue': 'world!',
                                        'oldvalue': 'world'}}}

Diferença de string 2

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!\nGoodbye!\n1\n2\nEnd"}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n1\n2\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { "root[4]['b']": { 'diff': '--- \n'
                                                '+++ \n'
                                                '@@ -1,5 +1,4 @@\n'
                                                '-world!\n'
                                                '-Goodbye!\n'
                                                '+world\n'
                                                ' 1\n'
                                                ' 2\n'
                                                ' End',
                                        'newvalue': 'world\n1\n2\nEnd',
                                        'oldvalue': 'world!\n'
                                                    'Goodbye!\n'
                                                    '1\n'
                                                    '2\n'
                                                    'End'}}}

>>> 
>>> print (ddiff['values_changed']["root[4]['b']"]["diff"])
--- 
+++ 
@@ -1,5 +1,4 @@
-world!
-Goodbye!
+world
 1
 2
 End

Tipo de alteração

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n\n\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'type_changes': { "root[4]['b']": { 'newtype': <class 'str'>,
                                      'newvalue': 'world\n\n\nEnd',
                                      'oldtype': <class 'list'>,
                                      'oldvalue': [1, 2, 3]}}}

Lista diferença

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{'iterable_item_removed': {"root[4]['b'][2]": 3, "root[4]['b'][3]": 4}}

Lista diferença 2:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'iterable_item_added': {"root[4]['b'][3]": 3},
  'values_changed': { "root[4]['b'][1]": {'newvalue': 3, 'oldvalue': 2},
                      "root[4]['b'][2]": {'newvalue': 2, 'oldvalue': 3}}}

Liste a diferença de ignorando ordem ou duplicata: (com os mesmos dicionários acima)

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2, ignore_order=True)
>>> print (ddiff)
{}

Lista que contém dicionário:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'dic_item_removed': ["root[4]['b'][2][2]"],
  'values_changed': {"root[4]['b'][2][1]": {'newvalue': 3, 'oldvalue': 1}}}

Conjuntos:

>>> t1 = {1, 2, 8}
>>> t2 = {1, 2, 3, 5}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (DeepDiff(t1, t2))
{'set_item_added': ['root[3]', 'root[5]'], 'set_item_removed': ['root[8]']}

Tuplas nomeadas:

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> t1 = Point(x=11, y=22)
>>> t2 = Point(x=11, y=23)
>>> pprint (DeepDiff(t1, t2))
{'values_changed': {'root.y': {'newvalue': 23, 'oldvalue': 22}}}

Objetos personalizados:

>>> class ClassA(object):
...     a = 1
...     def __init__(self, b):
...         self.b = b
... 
>>> t1 = ClassA(1)
>>> t2 = ClassA(2)
>>> 
>>> pprint(DeepDiff(t1, t2))
{'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}

Atributo do objeto adicionado:

>>> t2.c = "new attribute"
>>> pprint(DeepDiff(t1, t2))
{'attribute_added': ['root.c'],
 'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}

Se você está realmente analisando o desempenho, use Numpy!

Aqui está o caderno completo como uma essência no Github com comparação entre List, Numpy e Pandas.

https://gist.github.com/denfromufa/2821ff59b02e9482be15d27f2bbd4451

enter image description here

maneira mais simples,

usar set (). Diferença (set ())

list_a = [1,2,3]
list_b = [2,3]
print set(list_a).difference(set(list_b))

a resposta é set([1])

pode imprimir como uma lista,

print list(set(list_a).difference(set(list_b)))

Vou jogar, já que nenhuma das soluções atuais produz uma tupla:

temp3 = tuple(set(temp1) - set(temp2))

alternativamente:

#edited using @Mark Byers idea. If you accept this one as answer, just accept his instead.
temp3 = tuple(x for x in temp1 if x not in set(temp2))

Como as outras respostas que não rendem a tuple nessa direção, preserva a ordem

Pode ser feito usando o operador Python XOR.

  • Isso removerá as duplicatas em cada lista
  • Isso mostrará a diferença de temp1 de temp2 e temp2 de temp1.

set(temp1) ^ set(temp2)

Eu queria algo que levasse duas listas e pudesse fazer o que diff dentro bash faz. Como essa pergunta aparece primeiro quando você procura "Python Diff duas listas" e não é muito específico, postarei o que criei.

Usando SequenceMather a partir de difflib Você pode comparar duas listas como diff faz. Nenhuma das outras respostas dirá a posição em que a diferença ocorre, mas essa acontece. Algumas respostas dão a diferença apenas em uma direção. Alguns reordenam os elementos. Alguns não lidam com duplicatas. Mas esta solução oferece uma diferença verdadeira entre duas listas:

a = 'A quick fox jumps the lazy dog'.split()
b = 'A quick brown mouse jumps over the dog'.split()

from difflib import SequenceMatcher

for tag, i, j, k, l in SequenceMatcher(None, a, b).get_opcodes():
  if tag == 'equal': print('both have', a[i:j])
  if tag in ('delete', 'replace'): print('  1st has', a[i:j])
  if tag in ('insert', 'replace'): print('  2nd has', b[k:l])

Isso sai:

both have ['A', 'quick']
  1st has ['fox']
  2nd has ['brown', 'mouse']
both have ['jumps']
  2nd has ['over']
both have ['the']
  1st has ['lazy']
both have ['dog']

Obviamente, se o seu aplicativo fizer as mesmas suposições que as outras respostas fazem, você se beneficiará mais com elas. Mas se você está procurando um verdadeiro diff funcionalidade, então este é o único caminho a percorrer.

Por exemplo, nenhuma das outras respostas poderia lidar:

a = [1,2,3,4,5]
b = [5,4,3,2,1]

Mas este faz:

  2nd has [5, 4, 3, 2]
both have [1]
  1st has [2, 3, 4, 5]

Experimente isso:

temp3 = set(temp1) - set(temp2)

Isso pode ser ainda mais rápido que a compreensão da lista de Mark:

list(itertools.filterfalse(set(temp2).__contains__, temp1))

Aqui está um Counter Resposta para o caso mais simples.

Isso é mais curto que o acima que faz diferenças de mão dupla porque faz exatamente o que a pergunta faz: gerar uma lista do que está na primeira lista, mas não a segunda.

from collections import Counter

lst1 = ['One', 'Two', 'Three', 'Four']
lst2 = ['One', 'Two']

c1 = Counter(lst1)
c2 = Counter(lst2)
diff = list((c1 - c2).elements())

Como alternativa, dependendo das suas preferências de legibilidade, isso contribui para uma linha decente:

diff = list((Counter(lst1) - Counter(lst2)).elements())

Resultado:

['Three', 'Four']

Observe que você pode remover o list(...) Ligue se você está apenas iterando sobre isso.

Como essa solução usa contadores, ele lida com quantidades corretamente versus as muitas respostas baseadas em conjuntos. Por exemplo, nesta entrada:

lst1 = ['One', 'Two', 'Two', 'Two', 'Three', 'Three', 'Four']
lst2 = ['One', 'Two']

A saída é:

['Two', 'Two', 'Three', 'Three', 'Four']

Você pode usar um método ingênuo se os elementos do diffist forem classificados e conjuntos.

list1=[1,2,3,4,5]
list2=[1,2,3]

print list1[len(list2):]

ou com métodos de conjunto nativo:

subset=set(list1).difference(list2)

print subset

import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print "Naive solution: ", timeit.timeit('temp1[len(temp2):]', init, number = 100000)
print "Native set solution: ", timeit.timeit('set(temp1).difference(temp2)', init, number = 100000)

Solução ingênua: 0,0787101593292

Solução de conjunto nativo: 0,998837615564

Estou muito tarde no jogo para isso, mas você pode fazer uma comparação do desempenho de alguns dos código acima mencionados com isso, dois dos candidatos mais rápidos são,

list(set(x).symmetric_difference(set(y)))
list(set(x) ^ set(y))

Peço desculpas pelo nível elementar de codificação.

import time
import random
from itertools import filterfalse

# 1 - performance (time taken)
# 2 - correctness (answer - 1,4,5,6)
# set performance
performance = 1
numberoftests = 7

def answer(x,y,z):
    if z == 0:
        start = time.clock()
        lists = (str(list(set(x)-set(y))+list(set(y)-set(y))))
        times = ("1 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 1:
        start = time.clock()
        lists = (str(list(set(x).symmetric_difference(set(y)))))
        times = ("2 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 2:
        start = time.clock()
        lists = (str(list(set(x) ^ set(y))))
        times = ("3 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 3:
        start = time.clock()
        lists = (filterfalse(set(y).__contains__, x))
        times = ("4 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 4:
        start = time.clock()
        lists = (tuple(set(x) - set(y)))
        times = ("5 = " + str(time.clock() - start))
        return (lists,times)

    elif z == 5:
        start = time.clock()
        lists = ([tt for tt in x if tt not in y])
        times = ("6 = " + str(time.clock() - start))
        return (lists,times)

    else:    
        start = time.clock()
        Xarray = [iDa for iDa in x if iDa not in y]
        Yarray = [iDb for iDb in y if iDb not in x]
        lists = (str(Xarray + Yarray))
        times = ("7 = " + str(time.clock() - start))
        return (lists,times)

n = numberoftests

if performance == 2:
    a = [1,2,3,4,5]
    b = [3,2,6]
    for c in range(0,n):
        d = answer(a,b,c)
        print(d[0])

elif performance == 1:
    for tests in range(0,10):
        print("Test Number" + str(tests + 1))
        a = random.sample(range(1, 900000), 9999)
        b = random.sample(range(1, 900000), 9999)
        for c in range(0,n):
            #if c not in (1,4,5,6):
            d = answer(a,b,c)
            print(d[1])

Esta é outra solução:

def diff(a, b):
    xa = [i for i in set(a) if i not in b]
    xb = [i for i in set(b) if i not in a]
    return xa + xb

Se você encontrar TypeError: unhashable type: 'list' Você precisa transformar listas ou conjuntos em tuplas, por exemplo

set(map(tuple, list_of_lists1)).symmetric_difference(set(map(tuple, list_of_lists2)))

Veja também Como comparar uma lista de listas/conjuntos no Python?

Aqui estão alguns simples, Preservação de pedidos Maneiras de diferenciar duas listas de cordas.

Código

Uma abordagem incomum usando pathlib:

import pathlib


temp1 = ["One", "Two", "Three", "Four"]
temp2 = ["One", "Two"]

p = pathlib.Path(*temp1)
r = p.relative_to(*temp2)
list(r.parts)
# ['Three', 'Four']

Isso pressupõe que ambas as listas contenham strings com começos equivalentes. Veja o documentos para mais detalhes. Observe que não é particularmente rápido em comparação às operações definidas.


Uma implementação direta usando itertools.zip_longest:

import itertools as it


[x for x, y in it.zip_longest(temp1, temp2) if x != y]
# ['Three', 'Four']

versão de linha única de arulmr solução

def diff(listA, listB):
    return set(listA) - set(listB) | set(listA) -set(listB)

Se você quiser algo mais parecido com uma mudança ... poderia usar o contador

from collections import Counter

def diff(a, b):
  """ more verbose than needs to be, for clarity """
  ca, cb = Counter(a), Counter(b)
  to_add = cb - ca
  to_remove = ca - cb
  changes = Counter(to_add)
  changes.subtract(to_remove)
  return changes

lista = ['one', 'three', 'four', 'four', 'one']
listb = ['one', 'two', 'three']

In [127]: diff(lista, listb)
Out[127]: Counter({'two': 1, 'one': -1, 'four': -2})
# in order to go from lista to list b, you need to add a "two", remove a "one", and remove two "four"s

In [128]: diff(listb, lista)
Out[128]: Counter({'four': 2, 'one': 1, 'two': -1})
# in order to go from listb to lista, you must add two "four"s, add a "one", and remove a "two"

Podemos calcular a interseção menos a união de listas:

temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two', 'Five']

set(temp1+temp2)-(set(temp1)&set(temp2))

Out: set(['Four', 'Five', 'Three']) 

Isso pode ser resolvido com uma linha. A pergunta recebe duas listas (temp1 e temp2) retornam sua diferença em uma terceira lista (TEMP3).

temp3 = list(set(temp1).difference(set(temp2)))

Digamos que temos duas listas

list1 = [1, 3, 5, 7, 9]
list2 = [1, 2, 3, 4, 5]

Podemos ver nas duas listas acima que os itens 1, 3, 5 existem na lista2 e os itens 7, 9 não. Por outro lado, os itens 1, 3, 5 existem na lista1 e os itens 2, 4 não.

Qual é a melhor solução para retornar uma nova lista que contém itens 7, 9 e 2, 4?

Todas as respostas acima encontram a solução, agora qual é o mais ideal?

def difference(list1, list2):
    new_list = []
    for i in list1:
        if i not in list2:
            new_list.append(i)

    for j in list2:
        if j not in list1:
            new_list.append(j)
    return new_list

contra

def sym_diff(list1, list2):
    return list(set(list1).symmetric_difference(set(list2)))

Usando Timeit, podemos ver os resultados

t1 = timeit.Timer("difference(list1, list2)", "from __main__ import difference, 
list1, list2")
t2 = timeit.Timer("sym_diff(list1, list2)", "from __main__ import sym_diff, 
list1, list2")

print('Using two for loops', t1.timeit(number=100000), 'Milliseconds')
print('Using two for loops', t2.timeit(number=100000), 'Milliseconds')

retorna

[7, 9, 2, 4]
Using two for loops 0.11572412995155901 Milliseconds
Using symmetric_difference 0.11285737506113946 Milliseconds

Process finished with exit code 0

Aqui está uma maneira simples de distinguir duas listas (qualquer que seja o conteúdo), você pode obter o resultado como mostrado abaixo:

>>> from sets import Set
>>>
>>> l1 = ['xvda', False, 'xvdbb', 12, 'xvdbc']
>>> l2 = ['xvda', 'xvdbb', 'xvdbc', 'xvdbd', None]
>>>
>>> Set(l1).symmetric_difference(Set(l2))
Set([False, 'xvdbd', None, 12])

Espero que isso seja útil.

(list(set(a)-set(b))+list(set(b)-set(a)))
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top