2012-03-05 43 views
6

我有n個數字列表。我想確保每個列表都包含特定列表的唯一元素。即其餘任何內容都沒有「共享」副本。
這對於兩個列表非常簡單,但是對於n個列表來說有點麻煩。清除python中多個列表中常用列表元素的最簡單方法

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

變爲:

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

爲什麼2不在三個列表中的任何一箇中,而4仍然存在於第一個列表中? – 2012-03-05 23:03:09

+1

如果訂單得到保留,您是否在意? – wim 2012-03-05 23:06:00

+0

使用一個包('default_dict')構建一個「看到」列表。將每個'mylist'列表(我稱之爲'sublist')替換爲一個匹配'seen'的生成器:如果找到了,不要將它包含在最終的'sublist'中。如果找不到,請將其添加到包中。 – Droogans 2012-03-05 23:13:19

回答

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

這真的很好,但我寧願不必導入計數器和鏈我猜,這可能會稍微減少運行時間(?)。 – LittleBobbyTables 2012-03-05 23:27:08

+0

!!!我正在尋找一種在我的答案中以優雅的方式做'chain(* mylist)'的方法。非常好。糟糕,我甚至不需要'.get()'就好像在我的回答中那樣,因爲它當然會被定義。我正在刪除我的答案,因爲你的答案几乎完全一樣,但嚴格要好一些。 – ninjagecko 2012-03-05 23:29:18

+2

@MatthewRNYC:你不應該害怕使用像這個答案所建議的基本集合。另外我可以看到'chain'和'Counter'構造函數都不是'O(N)'的原因。 – ninjagecko 2012-03-05 23:31:07

2

這確實它在線性時間內,通過2次。我假設你想在列表中保留重複項;如果沒有,這可以簡化一下:

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

這留下一次看到的項目,不知道如果OP想要.. – wim 2012-03-05 23:12:20

+0

@wim,謝謝,修正。 – senderle 2012-03-05 23:25:31

1

既然你不關心順序,可以輕鬆去除使用set減法和轉換回列表重複。這是一個怪物的一行:

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

注:,因爲重複的重新計算各列。這是不是很有效。這是否是問題取決於您的數據大小。

+1

這是一隻野獸!:) – LittleBobbyTables 2012-03-05 23:27:33

+0

雖然看起來像一個昂貴的操作。如果你有'm'元素的'n'列表,每個元素都有'O(n * n-1 * m)'(這只是爲了遍歷每個子列表的每個元素)。或者我錯了? – 2012-03-05 23:32:39

+0

不幸的是,我必須-1:這將重新計算每個列表的所有重複項,導致大致'O(N ^(3/2))'工作,假設子列表的數目就像'sqrt(N)'。它也不保留列表的順序(儘管如果列表已排序,您可以重新對它們進行排序,代價是乘法的'O(log(sublistN))'factor extra)。我個人會選擇'Counter'解決方案,我相信這是'O(N)'。 – ninjagecko 2012-03-05 23:36:03

0

set()是正確的方法。儘管你不必使用列表理解。

如果沒有額外的進口:

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

這是我的解決方案,使用Counter構建一套所有常見的數字,然後把它只是做了一組區別:

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 

例子:

>>> remove_common(mylist) 
[set([1, 3]), set([5, 6, 7]), set([8, 9])] 
相關問題