2016-12-13 19 views
17

Pracuję z listami i muszę je porównać, aby utworzyć nową listę konkretnych elementów. NpPython znajduje elementy w jednej liście, które nie są w innych

main_list=[] 
list_1=["a", "b", "c", "d", "e"] 
list_2=["a", "f", "c", "m"] 

trzeba cicle na list_1 i dodać na main_list = [] Wszystkie elementy, które nie pasują do list_2.

Wynik powinien być tak:

main_list=["f", "m"] 

Jak mogę to zrobić z Pythona?

+1

szukasz elementów 'list_2' które pojawiają się znikąd w' list_1' lub elementów w 'list_2', które nie są obecne w tym samym indeksie w' list_1'? –

Odpowiedz

8

(1) Możesz użyć NumPy's setdiff1d. Z response of Chinny84, jeśli związane są z unikalnych elementów, a następnie:

import numpy as np 
list_1 = ["a", "b", "c", "d", "e"] 
list_2 = ["a", "f", "c", "m"] 
main_list = np.setdiff1d(list_2,list_1) 

(2) W przeciwnym razie, należy main_list = np.setdiff1d(list_2,list_1, assume_unique=True)

Obie odpowiedzi daje ["f", "m"]. Jednakże, jeśli list_2 = ["a", "f", "c", "m", "m"], odpowiedź (1) daje ["f", "m"], ale odpowiedź (2) daje ["f", "m", "m"] (ponieważ unikalność każdego elementu w list_2 jest niematerialna).

1

Chciałbym zip listy razem, aby porównać je element po elemencie.

main_list = [b for a, b in zip(list1, list2) if a!= b] 
+0

Jeśli OP chce porównać element po elemencie (jest niejasne, przykład może pójść w obu kierunkach), to jest znacznie skuteczniejsze niż inne odpowiedzi, ponieważ jest to pojedyncze tanie przejście przez "listę" z pojedynczą nową listą 'będąc skonstruowanym, bez dodatkowych tymczasowych, bez kosztownych kontroli przechowawczych, itp. – ShadowRanger

+0

@ ShadowRanger to działałoby tylko dla elementowej różnicy, która jest kluczowym punktem –

+0

@fordprefect: Yup. [Moja własna odpowiedź] (https://stackoverflow.com/a/41126821/364696) obejmuje różnice niezależne od pozycji. – ShadowRanger

34

Można używać zestawów:

main_list = list(set(list_2) - set(list_1)) 

wyjściowa:

>>> list_1=["a", "b", "c", "d", "e"] 
>>> list_2=["a", "f", "c", "m"] 
>>> set(list_2) - set(list_1) 
set(['m', 'f']) 
>>> list(set(list_2) - set(list_1)) 
['m', 'f'] 

Per komentarzu @JonClements', tutaj jest porządniej wersja:

>>> list_1=["a", "b", "c", "d", "e"] 
>>> list_2=["a", "f", "c", "m"] 
>>> list(set(list_2).difference(list_1)) 
['m', 'f'] 
+0

Jest to dobre, jeśli zależy nam tylko na elementach "unikatowych", ale jeśli mamy na przykład wiele "m", to tego nie wykryjemy. – Chinny84

+0

To prawda. Zakładałem, że plakat szuka wyjątkowych elementów. Przypuszczam, że zależy to od tego, co rozumie przez "konkretny". – nrlakin

+0

W rzeczywistości p.s. Nie głosowałem na twoją odpowiedź, szczególnie na niejasne oryginalne pytanie. – Chinny84

10

Użyj list comprehension tak:

main_list = [item for item in list_2 if item not in list_1] 

wyjściowa:

>>> list_1 = ["a", "b", "c", "d", "e"] 
>>> list_2 = ["a", "f", "c", "m"] 
>>> 
>>> main_list = [item for item in list_2 if item not in list_1] 
>>> main_list 
['f', 'm'] 
+1

Uwaga: dla większych 'list_1', chciałbyś wstępnie konwertować do' set'/'frozenset', np. 'set_1 = frozenset (list_1)', następnie 'main_list = [element dla elementu na liście_2, jeśli element nie jest w zestaw_1]', skracający czas sprawdzania z 'O (n)' na element do (z grubsza) 'O (1)' . – ShadowRanger

3
main_list=[] 
list_1=["a", "b", "c", "d", "e"] 
list_2=["a", "f", "c", "m"] 

for i in list_2: 
    if i not in list_1: 
     main_list.append(i) 

print(main_list) 

wyjściowa:

['f', 'm'] 
+0

Podobnie jak [odpowiednik rozwiązania opartego na zrozumieniu list] (http://stackoverflow.com/a/41125957/364696), będzie to powolne jeśli 'list_1' jest duże, a' list_2' ma nietrywialny rozmiar, ponieważ dotyczy 'len (list_2)' 'O (n)' skanów 'list_1', czyniąc go' O (n * m) '(gdzie' n' i 'm' są długościami odpowiednio' list_2' i 'list_1'). Jeśli konwertujesz 'list_1' na' set'/'frozenset' z góry, sprawdzenia zawiera można wykonać w' O (1) ', co powoduje, że suma operacji' O (n) 'na długości' list_2' (technicznie, 'O (max (n, m))', ponieważ robisz 'O (m)' działa, aby zrobić 'zestaw'). – ShadowRanger

0

Jeśli liczba wystąpień powinny być brane pod uwagę prawdopodobnie trzeba użyć czegoś jak collections.Counter:

list_1=["a", "b", "c", "d", "e"] 
list_2=["a", "f", "c", "m"] 
from collections import Counter 
cnt1 = Counter(list_1) 
cnt2 = Counter(list_2) 
final = [key for key, counts in cnt2.items() if cnt1.get(key, 0) != counts] 

>>> final 
['f', 'm'] 

Jak obiecałem to może również obsługiwać różnej liczby wystąpień jako „różnicę”:

list_1=["a", "b", "c", "d", "e", 'a'] 
cnt1 = Counter(list_1) 
cnt2 = Counter(list_2) 
final = [key for key, counts in cnt2.items() if cnt1.get(key, 0) != counts] 

>>> final 
['a', 'f', 'm'] 
1

Jeśli chcesz rozwiązanie jedno-liner (pomijając importu), które wymaga jedynie O(max(n, m)) pracy dla wejść o długości n i m, nie O(n * m) pracy, można to zrobić z the itertools module:

from itertools import filterfalse 

main_list = list(filterfalse(set(list_1).__contains__, list_2)) 

ta korzysta z funkcji czynnościowych zachodzących funkcji zwrotnej konstruktem jon, pozwalając mu utworzyć wywołanie jednorazowe i użyć go ponownie dla każdego elementu bez potrzeby przechowywania go gdzieś (ponieważ filterfalse przechowuje go wewnętrznie); Zrozumienie listy i wyrażeń generatora może to zrobić, ale jest brzydkie.†

że dostaje takie same wyniki w jednej linii jak:

main_list = [x for x in list_2 if x not in list_1] 

z prędkością:

set_1 = set(list_1) 
main_list = [x for x in list_2 if x not in set_1] 

oczywiście, jeśli porównania mają być pozycyjny, więc:

list_1 = [1, 2, 3] 
list_2 = [2, 3, 4] 

powinna produkować:

main_list = [2, 3, 4] 

(ponieważ wartość w list_2 ma mecz w tym samym indeksem w list_1), powinno się iść z Patrick's answer, która nie pociąga za sobą tymczasowe list s lub set s (nawet set s jest z grubsza O(1), mają wyższy "stały" czynnik na czeku niż proste kontrole równości) i obejmuje pracę O(min(n, m)), mniej niż jakakolwiek inna odpowiedź, a jeśli twój problem jest wrażliwy na pozycję, jest jedynym rozwiązaniem, gdy dopasowanie elementów pojawia się w niedopasowanych przesunięciach.

†: Sposobem na to samo z listowego jako jedną wkładką będzie nadużywać zagnieżdżone pętle, aby utworzyć i wartość cache (y) w „peryferyjnymi” pętli, np:

main_list = [x for set_1 in (set(list_1),) for x in list_2 if x not in set_1] 

, która również daje niewielką poprawę wydajności w Pythonie 3 (ponieważ teraz set_1 jest lokalnie zawarty w kodzie zrozumienia, a nie podniósł się z zagnieżdżonego zakresu dla każdego sprawdzenia, w Pythonie 2, który nie ma znaczenia, ponieważ Python 2 nie używać zamknięć do sprawdzania list, działają w tym samym zakresie, w którym są używane).

10

Nie wiem, dlaczego powyższe wyjaśnienia są tak skomplikowane, gdy masz rodzimych metod dostępnych:

main_list = list(set(list_2)-set(list_1)) 
+0

Zachowanie porządku może być przyczyną – Keith