我有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]
]
我有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]
]
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]]
這真的很好,但我寧願不必導入計數器和鏈我猜,這可能會稍微減少運行時間(?)。 – LittleBobbyTables 2012-03-05 23:27:08
!!!我正在尋找一種在我的答案中以優雅的方式做'chain(* mylist)'的方法。非常好。糟糕,我甚至不需要'.get()'就好像在我的回答中那樣,因爲它當然會被定義。我正在刪除我的答案,因爲你的答案几乎完全一樣,但嚴格要好一些。 – ninjagecko 2012-03-05 23:29:18
@MatthewRNYC:你不應該害怕使用像這個答案所建議的基本集合。另外我可以看到'chain'和'Counter'構造函數都不是'O(N)'的原因。 – ninjagecko 2012-03-05 23:31:07
這確實它在線性時間內,通過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]]
既然你不關心順序,可以輕鬆去除使用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]]
注:,因爲重複的重新計算各列。這是不是很有效。這是否是問題取決於您的數據大小。
這是一隻野獸!:) – LittleBobbyTables 2012-03-05 23:27:33
雖然看起來像一個昂貴的操作。如果你有'm'元素的'n'列表,每個元素都有'O(n * n-1 * m)'(這只是爲了遍歷每個子列表的每個元素)。或者我錯了? – 2012-03-05 23:32:39
不幸的是,我必須-1:這將重新計算每個列表的所有重複項,導致大致'O(N ^(3/2))'工作,假設子列表的數目就像'sqrt(N)'。它也不保留列表的順序(儘管如果列表已排序,您可以重新對它們進行排序,代價是乘法的'O(log(sublistN))'factor extra)。我個人會選擇'Counter'解決方案,我相信這是'O(N)'。 – ninjagecko 2012-03-05 23:36:03
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])]
這是我的解決方案,使用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])]
爲什麼2不在三個列表中的任何一箇中,而4仍然存在於第一個列表中? – 2012-03-05 23:03:09
如果訂單得到保留,您是否在意? – wim 2012-03-05 23:06:00
使用一個包('default_dict')構建一個「看到」列表。將每個'mylist'列表(我稱之爲'sublist')替換爲一個匹配'seen'的生成器:如果找到了,不要將它包含在最終的'sublist'中。如果找不到,請將其添加到包中。 – Droogans 2012-03-05 23:13:19