2013-08-12 9 views
5

Próbuję usunąć duplikaty z 2 list. więc napisałem tę funkcję:python usuń duplikaty z 2 list

a = ["abc", "def", "ijk", "lmn", "opq", "rst", "xyz"] 

b = ["ijk", "lmn", "opq", "rst", "123", "456", ] 

for i in b: 
    if i in a: 
     print "found " + i 
     b.remove(i) 

print b 

Ale uważam, że pasujące elementy po dopasowanym przedmiocie nie zostaną usunięte.

mogę prowadzić tak:

found ijk 
found opq 
['lmn', 'rst', '123', '456'] 

ale spodziewam spowodować tak:

[ '123', '456']

Jak mogę naprawić mój funkcji, aby robić to, co Chcę?

Dziękuję.

+0

i dało ci rozwiązanie, które zachowuje obie listy, w tej samej kolejności i usuwa duplikaty w każdym z nich. Sądzę, że tego właśnie szukałeś. –

Odpowiedz

9

Twój problem polega na tym, że zmieniasz listę, którą przeglądasz. Iteruj zamiast kopii listy.

for i in b[:]: 
    if i in a: 
     b.remove(i) 


>>> b 
['123', '456'] 

Ale, zamiast tego, w jaki sposób użyć zamiast tego zrozumienia ze spisu?

>>> a = ["abc", "def", "ijk", "lmn", "opq", "rst", "xyz"] 
>>> b = ["ijk", "lmn", "opq", "rst", "123", "456", ] 
>>> [elem for elem in b if elem not in a ] 
['123', '456'] 
+0

Jeśli lista 'a' rośnie dłużej, może się okazać, że przekształcenie jej w' zestaw' jest dużo bardziej wydajne ('x in s' jest O (1) dla zbiorów, O (n) dla list) zgodnie z http : //wiki.python.org/moin/TimeComplexity –

+0

@ Dvvvoter: Czy możesz zostawić komentarz na temat tego, co było nie tak z tą odpowiedzią? Naprawdę chciałbym to ulepszyć. :) –

+0

Dla przypomnienia nie padłem. :-) –

1

lub zestaw

set(b).difference(a) 

być uprzedzony zestawy nie będzie zachować porządek, jeśli to jest ważne

7

Co o

b= set(b) - set(a) 

Jeśli potrzebujesz możliwych powtórzeń w b również pojawiają się powtórzone w wyniku i/lub kolejności do zachowania, następnie

b= [ x for x in b if not x in a ] 

zrobiłaby.

+1

Ta odpowiedź została odrzucona raz. Czy ktoś może powiedzieć dlaczego? Każda poważna składnia/błąd koncepcyjny? Nie przyczyniając się do zadawanego pytania (i biorąc pod uwagę, że czasami niezwykle trudno jest zrozumieć, o co się pyta)? Zły angielski do niezrozumiałości? –

2

Pytałeś do usunąć oba wykazy powiela, tu jest moje rozwiązanie:

from collections import OrderedDict 
a = ["abc", "def", "ijk", "lmn", "opq", "rst", "xyz"] 
b = ["ijk", "lmn", "opq", "rst", "123", "456", ] 

x = OrderedDict.fromkeys(a) 
y = OrderedDict.fromkeys(b) 

for k in x: 
    if k in y: 
     x.pop(k) 
     y.pop(k) 


print x.keys() 
print y.keys() 

Wynik:

['abc', 'def', 'xyz'] 
['123', '456'] 

Dobrą rzeczą jest to, aby zachować kolejność obu elementów list

18

Oto, co się dzieje. Załóżmy, że masz tę listę:

['a', 'b', 'c', 'd'] 

i pętli nad każdym elementem na liście. Załóżmy, że aktualnie znajdujesz się w pozycji indeksu 1:

['a', 'b', 'c', 'd'] 
    ^
     | 
    index = 1 

...i usunąć element w indeksie 1, dając w ten sposób:

['a',  'c', 'd'] 
    ^
     | 
    index 1 

Po usunięciu elementu, pozostałe elementy przesuń w lewo, co daje to:

['a', 'c', 'd'] 
    ^
     | 
    index 1 

Wtedy gdy działa w pętli ponownie, pętla zwiększa indeks do 2, podając to:

['a', 'c', 'd'] 
      ^
      | 
     index = 2 

Zobacz, jak pominąłeś "c"? Lekcja jest następująca: nigdy nie usuwaj elementu z zapętlonej listy.

+4

Ta odpowiedź zawiera doskonale jasne wyjaśnienie przyczyny problemu, nie rozumiem, dlaczego uzyskał on negatywne głosowanie. – Bart

+0

Tak, masz rację. Mam nadzieję, że jest to błąd, którego nie można poprawić, ponieważ downvotes są zablokowane raz podane. –

+0

Być może przyczyną upadku jest brak działającego rozwiązania ... –

1

Jednym ze sposobów uniknięcia problemu edytując listę podczas iteracji nad nim, jest użycie listowych:

a = ["abc", "def", "ijk", "lmn", "opq", "rst", "xyz"] 
b = ["ijk", "lmn", "opq", "rst", "123", "456", ] 
b = [x for x in b if not x in a] 
+0

To samo rozwiązanie opublikował 1h temu przez Mario Rossi i Sukrit Kalra. –

+0

Być może @Mayur Patel zaczął pisać w tym samym czasie niż ja. To jest temat dla meta (chyba): blokowanie pytań, gdy 1 (lub może 2) ludzie odpowiadają na nie (przez pewien czas?) Lub przynajmniej wskazanie, ile osób odpowiada na nie. Mam na myśli, zanim odpowiedzi zostaną ** zaksięgowane **. Ale jestem noobie. Jeśli coś takiego już tam jest, daj mi znać. –

0

Istnieje już wiele odpowiedzi na temat „jak można to naprawić?”, Więc jest to a „jak można ją poprawić i być bardziej pythonic?”: od tego, co chcesz osiągnąć to, aby uzyskać różnicę między listy b i listy a, należy użyć operacji odejmowania na zbiorach (operations on sets):

>>> a = ["abc", "def", "ijk", "lmn", "opq", "rst", "xyz"] 
>>> b = ["ijk", "lmn", "opq", "rst", "123", "456", ] 
>>> s1 = set(a) 
>>> s2 = set(b) 
>>> s2 - s1 
set(['123', '456'])