2013-08-12 63 views
5

Tôi đang cố xóa các từ khóa trùng lặp khỏi 2 danh sách. vì vậy tôi đã viết chức năng này:python xóa các bản sao khỏi 2 danh sách

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 

Nhưng tôi thấy rằng các mục phù hợp sau một mục phù hợp sẽ không bị xóa.

tôi nhận được kết quả như thế này:

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

nhưng tôi hy vọng kết quả như thế này:

[ '123', '456']

Làm thế nào tôi có thể sửa chữa chức năng của tôi để làm gì Tôi muốn?

Cảm ơn bạn.

+0

tôi đã cung cấp cho bạn giải pháp giữ cả danh sách của bạn, theo cùng một thứ tự và loại bỏ các bản sao trong mỗi người trong số họ. Tôi đoán đây là những gì bạn đang tìm kiếm. –

Trả lời

9

Sự cố của bạn dường như là bạn đang thay đổi danh sách bạn đang lặp lại. Thay vào đó hãy lặp lại bản sao của danh sách.

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


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

Tuy nhiên, về cách sử dụng hiểu danh sách thay thế?

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

Nếu danh sách 'a' phát triển lâu hơn thì có thể biến nó thành' bộ' hiệu quả hơn rất nhiều ('x trong s' là O (1) cho các bộ, O (n) cho danh sách) theo http : //wiki.python.org/moin/TimeComplexity –

+0

@Downvoter: Bạn có thể vui lòng để lại nhận xét về những gì đã xảy ra với câu trả lời này không? Tôi thực sự muốn cải thiện nó. :) –

+0

Đối với hồ sơ, tôi đã không downvote. :-) –

1

hoặc một tập

set(b).difference(a) 

được cân nhắc kỹ càng bộ sẽ không giữ gìn trật tự nếu đó là quan trọng

7

gì về

b= set(b) - set(a) 

Nếu bạn cần lặp đi lặp lại có thể trong b đến cũng xuất hiện lặp lại trong kết quả và/hoặc thứ tự được bảo tồn, sau đó

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

sẽ thực hiện.

+1

Câu trả lời này đã được bình chọn một lần. Ai có thể nói tại sao? Bất kỳ cú pháp nghiêm trọng/lỗi khái niệm nào? Không đóng góp cho câu hỏi được hỏi (và xem xét đôi khi nó là vô cùng khó khăn để hiểu những gì đang được yêu cầu)? Tiếng Anh xấu đến mức không thể hiểu được? –

2

Bạn đã yêu cầu loại bỏ cả danh sách bản sao, đây là giải pháp của tôi:

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

Kết quả:

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

Những điều tốt đẹp ở đây là bạn giữ trật tự trong cả hai danh sách các mặt hàng

18

Đây là những gì đang diễn ra. Giả sử bạn có danh sách này:

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

và bạn đang lặp qua mọi thành phần trong danh sách. Giả sử bạn hiện đang ở vị trí chỉ mục 1:

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

...và bạn loại bỏ phần tử ở vị trí chỉ số 1 cho bạn điều này:

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

Sau khi loại bỏ mặt hàng đó, các mặt hàng khác trượt sang bên trái, đem lại cho bạn này:

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

Sau đó, khi vòng lặp chạy một lần nữa, vòng lặp tăng chỉ mục lên 2, cung cấp cho bạn điều này:

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

Xem cách bạn bỏ qua 'c'? Bài học là: không bao giờ xóa một phần tử từ danh sách mà bạn đang lặp lại.

+4

Câu trả lời này chứa một lời giải thích hoàn toàn rõ ràng về nguyên nhân của sự cố, tôi không hiểu tại sao nó lại bị bỏ phiếu tiêu cực. – Bart

+0

Có, bạn đã đúng. Hy vọng rằng đó là một sai lầm mà không thể được sửa chữa vì downvotes bị khóa một lần nhất định. –

+0

Có lẽ lý do cho các downvotes là sự vắng mặt của một giải pháp làm việc ... –

1

Một cách để tránh các vấn đề về chỉnh sửa danh sách trong khi bạn lặp trên nó, là sử dụng comprehensions:

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

Cùng một giải pháp được đăng cách đây 1 giờ bởi Mario Rossi và Sukrit Kalra. –

+0

Có lẽ @Mayur Patel bắt đầu viết nó cùng một lúc hơn tôi. Đây là một chủ đề cho meta (tôi đoán): hoặc chặn các câu hỏi khi 1 (hoặc có lẽ 2) mọi người đang trả lời chúng (trong một khoảng thời gian nhất định?), Hoặc ít nhất là một dấu hiệu cho biết có bao nhiêu người khác đang trả lời chúng. Ý tôi là trước khi câu trả lời được đăng **. Tôi là một noobie, mặc dù. Nếu một cái gì đó như thế này đã có, xin vui lòng cho tôi biết. –

0

Đã có nhiều câu trả lời về "làm thế nào bạn có thể sửa chữa nó?", Vì vậy đây là một "làm thế nào bạn có thể cải thiện nó và được pythonic hơn?": từ những gì bạn muốn đạt được là để có được sự khác biệt giữa danh sách b và danh sách a, bạn nên sử dụng hoạt động khác biệt trên bộ (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']) 
Các vấn đề liên quan