Uzyskaj różnicę między dwiema listami

809

Mam dwie listy w Pythonie, takie jak te:

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

Muszę utworzyć trzecią listę z elementami z pierwszej listy, których nie ma na drugiej. Z przykładu muszę uzyskać:

temp3 = ['Three', 'Four']

Czy są jakieś szybkie sposoby bez cykli i sprawdzania?

Max Frai
źródło
14
Czy elementy są gwarantowane niepowtarzalne? Jeśli masz temp1 = ['One', 'One', 'One']i temp2 = ['One']chcesz ['One', 'One']wrócić []?
Michael Mrozek,
@ michael-mrozek są wyjątkowe.
Max Frai,
12
Czy chcesz zachować porządek elementów?
Mark Byers,

Odpowiedzi:

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

Uważaj na to

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

gdzie możesz się spodziewać / chcesz, aby był równy set([1, 3]). Jeśli chcesz set([1, 3])jako odpowiedź, musisz użyć set([1, 2]).symmetric_difference(set([2, 3])).

ars
źródło
27
@Drewdin: Listy nie obsługują operandu „-”. Zestawy jednak tak robią i to, co pokazano powyżej, jeśli przyjrzysz się uważnie.
Godsmith
1
dzięki, skończyło się na użyciu set (ListA) .symmetric_difference (ListB)
Drewdin
43
różnicę symetryczną można zapisać za pomocą: ^ (set1 ^ set2)
Bastian
10
Czy mógłbyś edytować swoją odpowiedź i wskazać, że to zwraca tylko temp1-temp2? .. Jak już powiedziano, aby zwrócić wszystkie różnice, musisz użyć różnicy systemowej: list (set (temp1) ^ set (temp2))
rkachach
Dlaczego dostaję, TypeError: 'str' object is not callablekiedy wykonuję tę operację a = [1,2,2,2,3]ib = [2]
d8aninja
475

Wszystkie istniejące rozwiązania oferują jedno lub drugie z:

  • Szybsza niż wydajność O (n * m).
  • Zachowaj kolejność listy wprowadzania.

Ale jak dotąd żadne rozwiązanie nie ma obu. Jeśli chcesz obu, spróbuj tego:

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

Test wydajności

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)

Wyniki:

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

Metoda, którą przedstawiłem, a także zachowanie porządku jest również (nieco) szybsza niż odejmowanie zestawu, ponieważ nie wymaga budowy niepotrzebnego zestawu. Różnica wydajności byłaby bardziej zauważalna, gdyby pierwsza lista była znacznie dłuższa niż druga i jeśli mieszanie jest kosztowne. Oto drugi test, który to pokazuje:

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

Wyniki:

11.3836875916 # ars' answer
3.63890368748 # this answer (3 times faster!)
37.7445402279 # matt b's answer
Mark Byers
źródło
2
Dodatkowe wsparcie dla tej odpowiedzi: natrafiłem na przypadek użycia, w którym zachowanie kolejności listy było ważne dla wydajności. Podczas pracy z obiektami tarinfo lub zipinfo korzystałem z zestawu odejmowania. Aby wykluczyć niektóre obiekty tarinfo z wydobywania z archiwum. Tworzenie nowej listy było szybkie, ale bardzo wolne podczas rozpakowywania. Powód przede wszystkim mnie uniknął. Okazuje się, że zmiana kolejności listy obiektów tarinfo spowodowała ogromny spadek wydajności. Przejście na metodę rozumienia listy uratowało dzień.
Ray Thompson,
@MarkByers - być może powinienem napisać w tym celu zupełnie nowe pytanie. Ale jak miałoby to działać w przypadku forloopa? Na przykład, jeśli moje temp1 i temp2 ciągle się zmieniają .. i chcę dołączyć nowe informacje do temp3?
Ason
@MarkByers - brzmi dobrze. Zastanowię się przez chwilę. ale +1 za świetne rozwiązanie.
Ason,
Zgadzam się z @Dejel >>> temp1 = [„One”, „Two”, „Three”, „Four”] >>> temp2 = [„One”, „Two”, „Six”] >>> s = set (temp2) >>> temp3 = [x dla x w temp1, jeśli x nie jest w s] >>> temp3 ['Three', 'Four']
Earlonils
3
@hckck Ponieważ sprawdzanie przynależności do listy jest operacją O (n) (iteracja po całej liście), ale sprawdzanie przynależności do zbioru to O (1).
Mark Byers,
86
temp3 = [item for item in temp1 if item not in temp2]
matowy b
źródło
15
Przechodząc temp2do zestawu przed pozwoliłoby to nieco bardziej wydajny.
lunaryorn
3
To prawda, zależy, czy Ockonal troszczy się o duplikaty, czy nie (oryginalne pytanie nie mówi)
Matt B
2
Komentarz mówi, że (listy | krotki) nie mają duplikatów.
1
Poparłem twoją odpowiedź, ponieważ na początku myślałem, że masz rację co do duplikatów. Ale item not in temp2i item not in set(temp2)zawsze zwróci te same wyniki, niezależnie od tego, czy są duplikaty, czy nie temp2.
arekolek
5
W górę głosuj za niewymaganie możliwości skrócenia elementów listy.
Brent
23

Różnicę między dwiema listami (powiedzmy list1 i list2) można znaleźć za pomocą następującej prostej funkcji.

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)

lub

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

Korzystając z powyższej funkcji, różnicę można znaleźć za pomocą diff(temp2, temp1)lub diff(temp1, temp2). Oba dadzą wynik ['Four', 'Three']. Nie musisz się martwić o kolejność listy lub o to, która lista ma zostać podana jako pierwsza.

Dokumentacja w Pythonie

arulmr
źródło
7
Dlaczego nie ustawić (list1) .symmetric_difference (set (list2))?
swietyy
20

Jeśli chcesz rekurencyjnie różnicę, napisałem pakiet dla Pythona: https://github.com/seperman/deepdiff

Instalacja

Zainstaluj z PyPi:

pip install deepdiff

Przykładowe użycie

Importowanie

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

Ten sam obiekt zwraca pusty

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

Rodzaj przedmiotu zmienił się

>>> 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}}}

Wartość przedmiotu uległa zmianie

>>> 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}}}

Element został dodany i / lub usunięty

>>> 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}}}

Różnica w strunach

>>> 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'}}}

Różnica w strunach 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

Zmiana typu

>>> 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 różnic

>>> 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}}

Różnica między listami 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}}}

Lista różnic ignoruje kolejność lub duplikaty: (z tymi samymi słownikami jak powyżej)

>>> 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 zawierająca słownik:

>>> 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}}}

Zestawy:

>>> 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]']}

Nazwane krotki:

>>> 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}}}

Niestandardowe obiekty:

>>> 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}}}

Dodano atrybut obiektu:

>>> t2.c = "new attribute"
>>> pprint(DeepDiff(t1, t2))
{'attribute_added': ['root.c'],
 'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}
Seperman
źródło
20

Można to zrobić za pomocą operatora XOR w Pythonie.

  • Spowoduje to usunięcie duplikatów z każdej listy
  • To pokaże różnicę temp1 od temp2 i temp2 od temp1.

set(temp1) ^ set(temp2)
SuperNova
źródło
działa, ale dlaczego?
ZakS
najlepsza odpowiedź!
Artsiom Praneuski
co za odpowiedź! tak pytoniczny !!!! niesamowite
toing_toing
18

najprostszy sposób,

użyj set (). różnica (set ())

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

odpowiedź to set([1])

można wydrukować jako listę,

print list(set(list_a).difference(set(list_b)))
Mohideen bin Mohammed
źródło
14

Jeśli naprawdę szukasz wydajności, użyj numpy!

Oto pełny notatnik jako gist na githubie z porównaniem list, numpy i pand.

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

wprowadź opis zdjęcia tutaj

denfromufa
źródło
zaktualizowałem notes w linku, a także zrzut ekranu. Zaskakujące jest to, że pandy są wolniejsze niż numpy, nawet przy wewnętrznym przełączaniu na hashtable. Częściowo może to być spowodowane upcastingiem do int64.
denfromufa
13

rzucę się, ponieważ żadne z obecnych rozwiązań nie daje krotki:

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

alternatywnie:

#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))

Podobnie jak inne nie-krotki dające odpowiedzi w tym kierunku, zachowuje porządek

aaronasterling
źródło
11

Chciałem coś, co będzie trwać dwa wykazy i może robić to, co diffsię bashrobi. Ponieważ to pytanie pojawia się jako pierwsze, gdy wyszukujesz „python diff two list” i nie jest zbyt szczegółowe, opublikuję to, co wymyśliłem.

Używając SequenceMatherz difflibmożesz porównać dwie listy jak diffrobi. Żadna z pozostałych odpowiedzi nie wskaże Ci miejsca, w którym występuje różnica, ale ta robi. Niektóre odpowiedzi podają różnicę tylko w jednym kierunku. Niektórzy zmieniają kolejność elementów. Niektóre nie obsługują duplikatów. Ale to rozwiązanie daje prawdziwą różnicę między dwiema listami:

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])

To daje:

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']

Oczywiście, jeśli Twoja aplikacja przyjmuje te same założenia, co inne odpowiedzi, skorzystasz z nich najbardziej. Ale jeśli szukasz prawdziwej difffunkcjonalności, jest to jedyna droga.

Na przykład żadna z pozostałych odpowiedzi nie mogła obsłużyć:

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

Ale ten robi:

  2nd has [5, 4, 3, 2]
both have [1]
  1st has [2, 3, 4, 5]
arekolek
źródło
10

Spróbuj tego:

temp3 = set(temp1) - set(temp2)
Maciej Kucharz
źródło
10

może to być nawet szybsze niż zrozumienie listy Marka:

list(itertools.filterfalse(set(temp2).__contains__, temp1))
Mohammed
źródło
7
Może chciałbym dołączyć from itertools import filterfalsetutaj bit. Zauważ też, że to nie zwraca sekwencji jak inne, zwraca iterator.
Matt Luongo,
7

Oto Counterodpowiedź na najprostszy przypadek.

Jest to krótszy niż powyższy, który robi dwukierunkowe różnice, ponieważ robi dokładnie to, o co pyta pytanie: generuje listę tego, co jest na pierwszej liście, ale nie na drugiej.

from collections import Counter

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

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

Alternatywnie, w zależności od preferencji czytelności, tworzy przyzwoitą jednowarstwową:

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

Wynik:

['Three', 'Four']

Pamiętaj, że możesz usunąć list(...)połączenie, jeśli tylko wykonujesz iterację.

Ponieważ to rozwiązanie wykorzystuje liczniki, odpowiednio obsługuje ilości w porównaniu z wieloma odpowiedziami opartymi na zestawie. Na przykład na tym wejściu:

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

Dane wyjściowe to:

['Two', 'Two', 'Three', 'Three', 'Four']
Taylor Edmiston
źródło
5

Możesz użyć naiwnej metody, jeśli elementy difflist zostaną posortowane i ustawione.

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

print list1[len(list2):]

lub metodami natywnymi:

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)

Naiwny roztwór: 0,0787101593292

Rozwiązanie zestawu natywnego: 0,998837615564

soundcorner
źródło
5

Trochę spóźniłem się na tę grę, ale możesz porównać wydajność niektórych z wyżej wspomnianego kodu z tym, dwóch najszybszych konkurentów,

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

Przepraszam za podstawowy poziom kodowania.

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])
Alex Jacob
źródło
5

Oto kilka prostych, zachowujących porządek sposobów różnicowania dwóch list ciągów.

Kod

Nietypowe podejście wykorzystujące 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']

Zakłada się, że obie listy zawierają ciągi o równoważnych początkach. Więcej informacji można znaleźć w dokumentacji . Uwaga: nie jest szczególnie szybki w porównaniu do operacji ustawionych.


Prosta implementacja wykorzystująca itertools.zip_longest:

import itertools as it


[x for x, y in it.zip_longest(temp1, temp2) if x != y]
# ['Three', 'Four']
pylang
źródło
1
Rozwiązanie itertools działa, gdy tylko elementy temp1i temp2linia się dobrze. Jeśli na przykład odwrócisz elementy temp2lub wstawisz inną wartość na początku temp2, listcomp zwróci tylko te same elementy, co wtemp1
KenHBS 24.08.18
Tak, jest to cecha tych podejść. Jak wspomniano, rozwiązania te zachowują porządek - przyjmują pewną względną kolejność między listami. Nieuporządkowanym rozwiązaniem byłoby różnicowanie dwóch zestawów.
pylang
4

To jest inne rozwiązanie:

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
manhgd
źródło
4

Jeśli napotkasz TypeError: unhashable type: 'list', musisz zamienić listy lub zestawy w krotki, np

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

Zobacz także Jak porównać listę list / zestawów w pythonie?

kqw
źródło
4

Powiedzmy, że mamy dwie listy

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

z powyższych dwóch list możemy zobaczyć, że pozycje 1, 3, 5 istnieją na liście 2, a pozycje 7, 9 nie. Z drugiej strony pozycje 1, 3, 5 istnieją na liście 1, a pozycje 2, 4 nie.

Jakie jest najlepsze rozwiązanie, aby zwrócić nową listę zawierającą pozycje 7, 9 i 2, 4?

Wszystkie powyższe odpowiedzi znajdują rozwiązanie, co jest teraz najbardziej optymalne?

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

przeciw

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

Za pomocą timeit możemy zobaczyć wyniki

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')

zwroty

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

Process finished with exit code 0
Carson
źródło
3

jednowierszowa wersja rozwiązania arulmr

def diff(listA, listB):
    return set(listA) - set(listB) | set(listA) -set(listB)
sreemanth pulagam
źródło
3

jeśli chcesz czegoś bardziej jak zestaw zmian ... możesz użyć Counter

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"
Nick Franceschina
źródło
2

Możemy obliczyć przecięcie minus suma list:

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

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

Out: set(['Four', 'Five', 'Three']) 
Mohammad Etemaddar
źródło
2

Można to rozwiązać za pomocą jednej linii. Pytanie zawiera dwie listy (temp1 i temp2) zwracające różnicę w trzeciej liście (temp3).

temp3 = list(set(temp1).difference(set(temp2)))
fgaim
źródło
1

Oto prosty sposób na rozróżnienie dwóch list (niezależnie od zawartości), możesz uzyskać wynik, jak pokazano poniżej:

>>> 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])

Mam nadzieję, że to pomoże.

SK Venkat
źródło
0

Wolę używać konwersji do zbiorów, a następnie funkcji „różnic ()”. Pełny kod to:

temp1 = ['One', 'Two', 'Three', 'Four'  ]                   
temp2 = ['One', 'Two']
set1 = set(temp1)
set2 = set(temp2)
set3 = set1.difference(set2)
temp3 = list(set3)
print(temp3)

Wynik:

>>>print(temp3)
['Three', 'Four']

Najłatwiejsze do podkreślenia, a także w przyszłości, jeśli będziesz pracować z dużymi danymi, przekształcenie ich w zestawy usunie duplikaty, jeśli duplikaty nie będą wymagane. Mam nadzieję, że to pomoże ;-)

Shakhyar Gogoi
źródło
-1
(list(set(a)-set(b))+list(set(b)-set(a)))
nadhem
źródło
3
Czy poza udzieleniem odpowiedzi możesz wyjaśnić, jak to działa / dotyczy tego konkretnego problemu? Odpowiedzi i rozwiązania są świetne, ale szczegółowe przewodniki i wyjaśnienia są nieskończenie lepsze.
Busse,
-1
def diffList(list1, list2):     # returns the difference between two lists.
    if len(list1) > len(list2):
        return (list(set(list1) - set(list2)))
    else:
        return (list(set(list2) - set(list1)))

np. czy list1 = [10, 15, 20, 25, 30, 35, 40]i list2 = [25, 40, 35]wtedy zwrócona lista będzieoutput = [10, 20, 30, 15]

csg
źródło
Nie można tego zrobić w przypadku operacji różnicowej. Nawet w przypadku liczb całkowitych, jeśli powiesz funkcji wykonanie „a - b”, ma ona odejmować „b” tylko od „a”, bez względu na to, czy „b” jest większe niż „a”, czy w inny sposób. Podobnie jest w przypadku listy i zestawów. A - B i B - A oba mogą być prawidłowymi operacjami niezależnie od długości A i B, wystarczy wykluczyć zawartość B z A, aby wykonać A - B.
Abu Talha Danish