2012-02-24 259 views
61

我有一個列表的列表,我想刪除具有相同的鍵和值對的字典。在Python中刪除重複的列表中的字典

對於這個列表:[{'a': 123}, {'b': 123}, {'a': 123}]

我想退掉這:[{'a': 123}, {'b': 123}]

又如:

對於這個列表:[{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]

我想返回此: [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]

+0

您能告訴我們更多關於您試圖解決的實際問題嗎?這似乎是一個奇怪的問題。 – gfortune 2012-02-24 07:50:51

+0

我正在結合一些列表中的字典,並且有重複的內容。所以我需要刪除這些重複。 – Brenden 2012-02-24 07:51:51

+0

我在http://stackoverflow.com/questions/480214/how-do-you-remove-duplicates-from-a-list-in-python-whilst-preserving-order中找到了解決方案,但沒有使用'''set()''' – 2016-06-13 10:37:43

回答

116

試試這個:

[dict(t) for t in set([tuple(d.items()) for d in l])] 

該策略是將字典列表轉換爲元組列表,其中元組包含字典的項目。由於元組可以被散列化,因此可以使用set刪除重複項,然後使用dict從元組中重新創建字典。

其中:

  • l是原始列表
  • d是列表的字典
  • t是從字典

編輯創建的元組的一個之一:如果您想保留訂單,上面的單行不起作用,因爲set不會這樣做。然而,隨着幾行代碼,你也可以這樣做:

l = [{'a': 123, 'b': 1234}, 
     {'a': 3222, 'b': 1234}, 
     {'a': 123, 'b': 1234}] 

seen = set() 
new_l = [] 
for d in l: 
    t = tuple(d.items()) 
    if t not in seen: 
     seen.add(t) 
     new_l.append(d) 

print new_l 

輸出示例:

[{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}] 

注:由於@alexis指出,它可能會發生兩個詞典相同的按鍵和值,不會導致相同的元組。如果他們通過不同的添加/刪除鍵歷史記錄,可能會發生這種情況。如果您的問題屬於這種情況,請考慮按照他的建議對d.items()進行排序。

+0

在這個例子中,什麼是l? (in for d in l) – Brenden 2012-02-24 07:53:52

+0

@Brenden我已經用這些信息更新了答案。 'l'是你正在處理的清單。 – jcollado 2012-02-24 07:56:29

+13

不錯的解決方案,但它有一個bug:'d.items()'不保證以特定的順序返回元素。您應該執行'tuple(sorted(d.items()))'以確保您不會爲同一個鍵值對獲取不同的元組。 – alexis 2012-02-24 14:58:59

0

您可以使用一個集合,但您需要將字典轉換爲可哈希類型。

seq = [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}] 
unique = set() 
for d in seq: 
    t = tuple(d.iteritems()) 
    unique.add(t) 

獨特現在等於

set([(('a', 3222), ('b', 1234)), (('a', 123), ('b', 1234))]) 

要獲得類型的字典背:

[dict(x) for x in unique] 
8

有時候舊式的循環仍然是有用的。這個代碼比jcollado的更長一點,但是非常容易閱讀:

a = [{'a': 123}, {'b': 123}, {'a': 123}] 
b = [] 
for i in range(0, len(a)): 
    if a[i] not in a[i+1:]: 
     b.append(a[i]) 
+0

''0'in'range(0,len(a)) '沒有必要。 – 2018-02-08 18:47:58

22

另一條班輪基於列表解析:

>>> d = [{'a': 123}, {'b': 123}, {'a': 123}] 
>>> [i for n, i in enumerate(d) if i not in d[n + 1:]] 
[{'b': 123}, {'a': 123}] 

在這裏,因爲我們可以用dict比較,我們只保留元素這不在最初列表的其餘部分(這個概念只能通過索引n訪問,因此可以使用enumerate)。

+1

這也適用於由列表組成的詞典列表,與第一個答案 – gbozee 2015-12-02 08:09:00

+0

相比,這也適用於當您的詞典中可能有不可用的類型作爲值時,與頂級答案不同。 – 2016-02-01 12:43:22

+0

這比我選擇的答案更適合我。 – nikhilvj 2018-01-31 14:27:36

5

如果您想保留訂單,那麼你可以做

from collections import OrderedDict 
print OrderedDict((frozenset(item.items()),item) for item in data).values() 
# [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}] 

如果順序並不重要,那麼你可以做

print {frozenset(item.items()):item for item in data}.values() 
# [{'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}] 
8

其他的答案,如果你」是行不通的重新操作嵌套字典,如反序列化的JSON對象。對於這種情況下,您可以使用:

import json 
set_of_jsons = {json.dumps(d, sort_keys=True) for d in X} 
X = [json.loads(t) for t in set_of_jsons]