2012-03-05 41 views
6

Tôi có n danh sách số. Tôi muốn đảm bảo rằng mỗi danh sách chứa các phần tử duy nhất cho danh sách cụ thể đó. I E. Không có bản sao "được chia sẻ" trên bất kỳ phần nào còn lại.
Điều này thực sự dễ dàng thực hiện với hai danh sách, nhưng một chút phức tạp hơn với danh sách n.Cách sạch nhất để xóa các phần tử danh sách chung trên nhiều danh sách trong python

e.g. 
mylist = [ 
[1, 2, 3, 4], 
[2, 5, 6, 7], 
[4, 2, 8, 9] 
] 

trở thành:

mylist = [ 
[1, 3], 
[5, 6, 7], 
[8, 9] 
] 
+4

Tại sao 2 không nằm trong một trong ba danh sách, trong khi 4 không có trong danh sách đầu tiên? –

+1

Bạn có quan tâm nếu trật tự được bảo quản? – wim

+0

Sử dụng túi ('default_dict') để tạo danh sách" đã xem ". Thay thế mỗi danh sách của 'mylist' (tôi sẽ gọi nó là' sublist') với một trình tạo tìm kiếm 'matches': nếu tìm thấy, không bao gồm nó trong' sublist' cuối cùng. Nếu không tìm thấy, thêm nó vào túi. – Droogans

Trả lời

5
from collections import Counter 
from itertools import chain 

mylist = [ 
    [1,2,3,4], 
    [2,5,6,7,7], 
    [4,2,8,9] 
] 

counts = Counter(chain(*map(set,mylist))) 

[[i for i in sublist if counts[i]==1] for sublist in mylist] 
#[[1, 3], [5, 6, 7, 7], [8, 9]] 
+0

Điều này thực sự tốt đẹp, nhưng tôi không muốn phải nhập Counter và chuỗi Tôi đoán như thế này có thể làm giảm thời gian chạy (?). – LittleBobbyTables

+0

!!! Tôi đã tìm kiếm một cách để làm 'chuỗi (* mylist)' trong câu trả lời của tôi một cách thanh lịch. Rất đẹp. Rất tiếc, và tôi thậm chí không cần '.get()' như trong câu trả lời của tôi bởi vì tất nhiên nó sẽ luôn luôn được định nghĩa. Tôi đang xóa câu trả lời của tôi vì câu trả lời của bạn gần như giống hệt nhau nhưng hoàn toàn tốt hơn. – ninjagecko

+2

@MatthewRNYC: bạn không nên sợ sử dụng các bộ sưu tập cơ bản như câu trả lời này gợi ý. Ngoài ra tôi có thể thấy không có lý do gì mà 'chain' và constructor' Counter' sẽ không phải là cả hai 'O (N)'. – ninjagecko

2

này làm nó trong thời gian tuyến tính, 2 đèo. Tôi giả sử bạn muốn giữ lại các bản sao trong một danh sách; nếu không, điều này có thể được đơn giản hóa một chút:

>>> import collections, itertools 
>>> counts = collections.defaultdict(int) 
>>> for i in itertools.chain.from_iterable(set(l) for l in mylist): 
...  counts[i] += 1 
... 
>>> for l in mylist: 
...  l[:] = (i for i in l if counts[i] == 1) 
... 
>>> mylist 
[[1, 3], [5, 6, 7], [8, 9]] 
+0

Điều này để lại các mục được thấy một lần, không chắc chắn liệu OP có muốn .. – wim

+0

@wim, cảm ơn, đã sửa. – senderle

1

Vì bạn không quan tâm đến trật tự, bạn có thể dễ dàng loại bỏ trùng lặp bằng bộ trừ và chuyển đổi trở lại danh sách. Dưới đây là một con quái vật trong một liner:

>>> mylist = [ 
... [1, 2, 3, 4], 
... [2, 5, 6, 7], 
... [4, 2, 8, 9] 
... ] 
>>> mynewlist = [list(set(thislist) - set(element for sublist in mylist for element in sublist if sublist is not thislist)) for thislist in mylist] 
>>> mynewlist 
[[1, 3], [5, 6, 7], [8, 9]] 

Lưu ý: Đây không phải là rất hiệu quả vì bản sao được tính lại cho mỗi hàng. Cho dù đây là vấn đề hay không phụ thuộc vào kích thước dữ liệu của bạn.

+1

Đây là một con thú!:) – LittleBobbyTables

+0

Trông giống như một hoạt động đắt tiền. Nếu bạn có các danh sách 'n' với các phần tử' m', mỗi phần tử có một cái gì đó giống như 'O (n * n-1 * m)' (chỉ dùng để lặp qua từng phần tử của mỗi danh sách con). Hoặc là tôi sai? –

+0

Thật không may tôi phải -1: điều này tính toán lại tất cả các bản sao cho mỗi danh sách, kết quả là công việc 'O (N^(3/2))' giả định số lượng các danh sách con giống như 'sqrt (N)'. Nó cũng không bảo vệ thứ tự của một danh sách (mặc dù nếu các danh sách được sắp xếp, bạn có thể sắp xếp lại chúng, với chi phí của một nhân tố 'O (log (sublistN)' bổ sung). Cá nhân tôi sẽ đi với giải pháp 'Counter' mà tôi tin là 'O (N)'. – ninjagecko

0

set() là phương pháp phù hợp. mặc dù bạn không phải sử dụng tính năng hiểu danh sách.

Nếu không có thêm hàng nhập khẩu:

mylist = [ 
[1, 2, 3, 4], 
[2, 5, 6, 7], 
[4, 2, 8, 9] 
] 
>>> result_list = [] 
>>> for test_list in mylist: 
...  result_set = set(test_list) 
...  for compare_list in mylist: 
...   if test_list != compare_list: 
...    result_set = result_set - set(compare_list) 
...  result_list.append(result_set) 
... 
>>> result_list 
[set([1, 3]), set([5, 6, 7]), set([8, 9])] 
0

Đây là giải pháp của tôi, sử dụng Counter để xây dựng một tập hợp tất cả những con số thông thường, và sau đó nó chỉ làm một sự khác biệt thiết lập:

from collections import Counter 

def disjoin(lsts): 
    c = Counter(num for lst in lsts for num in lst) 
    common = set(x for x,v in c.items() if v > 1) 
    result = [] 
    for lst in lsts: 
     result.append(set(lst) - common) 
    return result 

Ví dụ:

>>> remove_common(mylist) 
[set([1, 3]), set([5, 6, 7]), set([8, 9])] 
Các vấn đề liên quan