2014-01-09 77 views
1

我有包含嵌套的字典詞典列表,像這樣:如何從Python中的列表中刪除重複的字典(使用嵌套字典)?

v0 = [ { 'a': 1, 'b': { 'c': 3 } }, 
     { 'a': 1, 'b': { 'c': 3 }, 'd': 4 }, 
     { 'a': 1 }, 
     { 'a': 1, 'b': { 'c': 3 } } ] 

如何刪除重複的列表元素,就像一個結果:

v1 = [ { 'a': 1, 'b': { 'c': 3 } }, 
     { 'a': 1, 'b': { 'c': 3 }, 'd': 4 }, 
     { 'a': 1 } ] 

我不關心順序,我只想要所有元素的集合。我見過很多類似的問題,但答案僅適用於列表中的簡單字典,而不是嵌套字典。例如:

v1 = [dict(t) for t in set([tuple(d.items()) for d in v0])] 

如果詞典不嵌套這會工作,而是因爲他們,我得到的錯誤「類型錯誤:unhashable類型:‘字典’」

回答

3
>>> v0 = [ { 'a': 1, 'b': { 'c': 3 } }, 
...  { 'a': 1, 'b': { 'c': 3 }, 'd': 4 }, 
...  { 'a': 1 }, 
...  { 'a': 1, 'b': { 'c': 3 } } ] 
>>> out = [] 
>>> for v in v0: 
...  if v not in out: 
...   out.append(v) 
...   
>>> out 
[{'a': 1, 'b': {'c': 3}}, {'a': 1, 'b': {'c': 3}, 'd': 4}, {'a': 1}] 
+1

重要的是要注意,這是O(n^2),而更有效的解決方案可以實現O(n)。 – univerio

+0

我最終使用這個。幸運的是,我的列表足夠小,以至於perf的命中並不重要,我覺得這是非常可讀的。 –

+0

@univerio:這是一個O(n^2)解決方案? v'中的v是O(n),'如果v不在out'中是O(1)。 –

1

首先,考慮是否有一個更簡單的想法就夠了。

如果你的字典集不是那麼大,最後一個字典真的很簡單-就像set一樣工作,除了每個搜索都是線性的而不是恆定時間。因此,相同的代碼將採用二次時間而不是線性,但它會起作用,並且它非常簡單,所以如果可以接受的話,就這樣做。

如果你的字典集可以得到相當大的,還是有一個相對容易的選擇:基於樹的集合像blistbintrees的那些可以在對數時間搜索。因此,相同的代碼將採用對數線性時間而不是線性 - 這通常足夠好,並且再次可以工作,並且簡單。

如果偶數對數線性過慢,則需要凍結字典類型和遞歸凍結函數。但是在PyPI和ActiveState上有一些實現,例如frozendict,並且自己編寫一個並不難。

事實上,你在這裏一半。 set([tuple(d.items()] for d in v0])做了一個單一的凍結級別,並用一組元組僞造了一個凍結的字典(這對許多用例都不起作用,但對你的用處不大)。所以你只需要遞歸地做同樣的事情。

0

如果你滿意的二次算法,然後

uniq = [x for n, x in enumerate(v0) if v0.index(x) == n] 

否則像

import json 
uniq = {json.dumps(x, sort_keys=True):x for x in v0}.values()