अजगर - अद्वितीय शब्दकोशों की सूची


158

मान लीजिए कि मुझे शब्दकोशों की एक सूची मिली है:

[
    {'id': 1, 'name': 'john', 'age': 34},
    {'id': 1, 'name': 'john', 'age': 34},
    {'id': 2, 'name': 'hanna', 'age': 30},
]

और मुझे अद्वितीय शब्दकोशों (डुप्लिकेट को हटाते हुए) की एक सूची प्राप्त करने की आवश्यकता है:

[
    {'id': 1, 'name': 'john', 'age': 34},
    {'id': 2, 'name': 'hanna', 'age': 30},
]

क्या कोई मुझे पायथन में इसे प्राप्त करने के लिए सबसे कुशल तरीके से मदद कर सकता है?


5
ये शब्दकोश कितने व्यापक हैं? क्या आपको डुप्लिकेट निर्धारित करने के लिए व्यक्तिगत विशेषता जाँच की आवश्यकता है, या उनमें पर्याप्त मूल्य की जाँच कर रहा है?
गद्देक

इन dicts को 8 कुंजी: मूल्य जोड़े मिले और सूची को 200 dicts मिले। उन्हें वास्तव में एक आईडी मिली है और मेरे लिए यह सुरक्षित है कि सूची से आईडी हटाए जाने पर सूची से डुप्लिकेट हटा दिया जाए।
लीमाफ


forzenset एक प्रभावी विकल्प है। set(frozenset(i.items()) for i in list)
अभिजीत

जवाबों:


238

तो कुंजी होने के साथ एक अस्थायी तय करें id। यह डुप्लिकेट को फ़िल्टर करता है। values()Dict की सूची हो जाएगा

पायथन 2.7 में

>>> L=[
... {'id':1,'name':'john', 'age':34},
... {'id':1,'name':'john', 'age':34},
... {'id':2,'name':'hanna', 'age':30},
... ]
>>> {v['id']:v for v in L}.values()
[{'age': 34, 'id': 1, 'name': 'john'}, {'age': 30, 'id': 2, 'name': 'hanna'}]

पायथन 3 में

>>> L=[
... {'id':1,'name':'john', 'age':34},
... {'id':1,'name':'john', 'age':34},
... {'id':2,'name':'hanna', 'age':30},
... ] 
>>> list({v['id']:v for v in L}.values())
[{'age': 34, 'id': 1, 'name': 'john'}, {'age': 30, 'id': 2, 'name': 'hanna'}]

पायथन 2.5 / 2.6 में

>>> L=[
... {'id':1,'name':'john', 'age':34},
... {'id':1,'name':'john', 'age':34},
... {'id':2,'name':'hanna', 'age':30},
... ] 
>>> dict((v['id'],v) for v in L).values()
[{'age': 34, 'id': 1, 'name': 'john'}, {'age': 30, 'id': 2, 'name': 'hanna'}]

@ जॉन ला रोय - एकाधिक विशेषताओं के आधार पर किसी सूची से शब्दकोश निकालने के लिए कोई भी इसका उपयोग कैसे कर सकता है, इसने कोशिश की, लेकिन काम नहीं करने वाला लगता है> {v ['उड़ान'] ['अकेला'] ['lat']: v के लिए v इन स्ट्रीम} .values ​​()
जॉर्ज

1
@JorgeVidinha यह मानते हुए कि प्रत्येक को str (या यूनिकोड) में डाला जा सकता है, यह कोशिश करें: {str(v['flight'])+':'+str(v['lon'])+','+str(v['lat']): v for v in stream}.values()यह आपके मूल्यों के आधार पर एक अद्वितीय कुंजी बनाता है। जैसे'MH370:-21.474370,86.325589'
२१:१६

4
@ जॉर्जव्दिन्हा, आप शब्दकोश कुंजी के रूप में एक टपल का उपयोग कर सकते हैं{(v['flight'], v['lon'], v['lat']): v for v in stream}.values()
जॉन ला रूय

ध्यान दें कि यह सूची में शब्दकोशों के क्रम को बदल सकता है! का उपयोग OrderedDictसे collections list(OrderedDict((v['id'], v) for v in L).values()) या प्रकार जिसके परिणामस्वरूप सूची है कि काम करता है के लिए आप बेहतर
गेवरा

यदि आपको सभी मानों पर विचार करने की आवश्यकता है, न कि केवल उस आईडी का उपयोग करें जिसका उपयोग list({str(i):i for i in L}.values())हम यहां str (i) का उपयोग करके एक अद्वितीय स्ट्रिंग बनाने के लिए करते हैं, जो उस शब्दकोश का प्रतिनिधित्व करता है जिसका उपयोग डुप्लिकेट को फ़िल्टर करने के लिए किया जाता है।
डेलबॉयज

79

एक सेट में सिर्फ सामान्य तत्वों को खोजने का सामान्य तरीका पायथन की setकक्षा का उपयोग करना है । बस सेट में सभी तत्वों को जोड़ें, फिर सेट को ए में परिवर्तित करें list, और डुप्लिकेट चले गए हैं।

समस्या, निश्चित रूप से, है कि set()केवल धोने योग्य प्रविष्टियां हो सकती हैं, और एक dictधोने योग्य नहीं है।

अगर मुझे यह समस्या थी, तो मेरा समाधान प्रत्येक dictको एक स्ट्रिंग में बदलना होगा जो प्रतिनिधित्व करता है dict, फिर set()स्ट्रिंग के मानों को एक के रूप में पढ़ने के लिए सभी स्ट्रिंग्स को एक में जोड़ें list()और वापस कन्वर्ट करें dict

dictस्ट्रिंग रूप में एक अच्छा प्रतिनिधित्व JSON प्रारूप है। और पायथन में JSON ( jsonनिश्चित रूप से) के लिए एक अंतर्निहित मॉड्यूल है ।

शेष समस्या यह है कि तत्वों का dictआदेश नहीं दिया जाता है, और जब पायथन dictएक JSON स्ट्रिंग में परिवर्तित होता है , तो आपको दो JSON स्ट्रिंग्स मिल सकते हैं जो समान शब्दकोशों का प्रतिनिधित्व करते हैं लेकिन समान तार नहीं हैं। आसान उपाय यह है कि sort_keys=Trueजब आप कॉल करें तो तर्क पास करें json.dumps()

संपादित करें: यह समाधान मान रहा था कि किसी दिए गए dictहिस्से में कोई अंतर हो सकता है। अगर हम यह मान सकते हैं कि प्रत्येक dictसमान "id"मूल्य के साथ हर एक दूसरे के dictसाथ मेल खाता है "id", तो यह ओवरकिल है; @ gnibbler का समाधान तेज और आसान होगा।

संपादित करें: अब आंद्रे लीमा की एक टिप्पणी स्पष्ट रूप से कह रही है कि यदि आईडी एक डुप्लिकेट है, तो यह मान लेना सुरक्षित है कि पूरा dictएक डुप्लिकेट है। तो यह उत्तर ओवरकिल है और मैं @ gnibbler के उत्तर की सिफारिश करता हूं।


मदद स्टीववे के लिए धन्यवाद। आपके उत्तर ने वास्तव में मुझे कुछ ज्ञान दिया जो मेरे पास नहीं था, क्योंकि मैंने अभी पायथन =) से शुरुआत की थी
लीमाफ

1
ओवरकिल को इस विशेष मामले में आईडी दिए जाने के दौरान, यह अभी भी एक उत्कृष्ट जवाब है!
जोश वार्ट्स

8
यह मेरी मदद करता है क्योंकि मेरे शब्दकोश में एक कुंजी नहीं है, और केवल इसकी सभी प्रविष्टियों द्वारा विशिष्ट रूप से पहचाना जाता है। धन्यवाद!
इस्सो

यह समाधान ज्यादातर समय काम करता है लेकिन स्केलिंग के साथ प्रदर्शन के मुद्दे हो सकते हैं लेकिन मुझे लगता है कि लेखक को यह पता है और इसलिए "आईडी" के साथ समाधान की सिफारिश करता है। प्रदर्शन संबंधी चिंताएँ: यह समाधान स्ट्रिंग को क्रमबद्ध करने और फिर डिसेररलाइज़ करने के लिए उपयोग करता है ... क्रमांकन / डीसर्लाइज़ करना महंगा संगणना है और आमतौर पर अच्छी तरह से स्केल नहीं करता है (आइटमों की संख्या n> 1e6 है या प्रत्येक शब्दकोश में> 1e6 आइटम या दोनों या यदि आपके पास है इसे कई बार निष्पादित करने के लिए> 1e6 या अक्सर।
ट्रेवर बॉयड स्मिथ

जैसे ही एक तरफ यह समाधान एक महान विहित उदाहरण दिखाता है कि आप अपने समाधान को क्यों डिजाइन करना चाहते हैं ... अर्थात यदि आपके पास एक आईडी है जो अद्वितीय है ... तो आप कुशलता से डेटा तक पहुंच सकते हैं ... यदि आप आलसी हैं और आपके पास एक आईडी नहीं है तो आपके डेटा का उपयोग अधिक महंगा है।
ट्रेवर बॉयड स्मिथ

21

यदि शब्द केवल विशिष्ट रूप से सभी आइटम (आईडी उपलब्ध नहीं है) से पहचाने जाते हैं, तो आप JSON का उपयोग करके उत्तर का उपयोग कर सकते हैं। निम्नलिखित एक विकल्प है जो JSON का उपयोग नहीं करता है, और जब तक सभी शब्दकोश मान अपरिवर्तनीय हैं, तब तक काम करेंगे

[dict(s) for s in set(frozenset(d.items()) for d in L)]

19

आप संख्यात्मक पुस्तकालय (केवल Python2.x के लिए काम करता है) का उपयोग कर सकते हैं:

   import numpy as np 

   list_of_unique_dicts=list(np.unique(np.array(list_of_dicts)))

इसे पायथन 3.x (और हाल के संस्करणों के साथ) काम करने के लिए, आपको dicts की सारणी को स्ट्रिंग्स के numpy सरणी में बदलने की आवश्यकता है, उदा।

list_of_unique_dicts=list(np.unique(np.array(list_of_dicts).astype(str)))

13
TypeError: unorderable types: dict() > dict()पायथन 3.5 में ऐसा करते समय त्रुटि प्राप्त करें ।
गुइलूचोन

16

यहाँ एक यथोचित कॉम्पैक्ट समाधान है, हालांकि मुझे संदेह है कि यह विशेष रूप से कुशल नहीं है (इसे हल्के ढंग से डालने के लिए):

>>> ds = [{'id':1,'name':'john', 'age':34},
...       {'id':1,'name':'john', 'age':34},
...       {'id':2,'name':'hanna', 'age':30}
...       ]
>>> map(dict, set(tuple(sorted(d.items())) for d in ds))
[{'age': 30, 'id': 2, 'name': 'hanna'}, {'age': 34, 'id': 1, 'name': 'john'}]

3
एक सूची वापस पाने के लिए पायथन 3 के map()साथ कॉल को घेर list()लें, अन्यथा यह एक mapवस्तु है।
dmn

अजगर में 3.6+ इस दृष्टिकोण का एक अतिरिक्त लाभ यह है कि सूची आदेश संरक्षित है
jnnnnn

7

चूंकि idडुप्लिकेट का पता लगाने के लिए पर्याप्त है, और यह idएक शब्दकोश के माध्यम से चलने योग्य है: उन्हें चलाएंid लिए कुंजी है। प्रत्येक कुंजी का मूल्य मूल शब्दकोश है।

deduped_dicts = dict((item["id"], item) for item in list_of_dicts).values()

पायथन 3 में, values()एक सूची वापस नहीं करता है; आपको उस अभिव्यक्ति के पूरे दाएं-बाएं भाग को लपेटना होगाlist() , और आप अभिव्यक्ति के मांस को एक आर्थिक समझ के रूप में अधिक आर्थिक रूप से लिख सकते हैं:

deduped_dicts = list({item["id"]: item for item in list_of_dicts}.values())

ध्यान दें कि परिणाम की संभावना मूल के समान क्रम में नहीं होगी। यदि यह एक आवश्यकता है, तो आप एक का उपयोग कर सकते हैंCollections.OrderedDict इसके बजायdict

एक तरफ के रूप में, यह सिर्फ एक शब्दकोश में डेटा रखने के लिए समझदारी का एक अच्छा सौदा कर सकता है जो कि idशुरू करने के लिए कुंजी का उपयोग करता है ।


6
a = [
{'id':1,'name':'john', 'age':34},
{'id':1,'name':'john', 'age':34},
{'id':2,'name':'hanna', 'age':30},
]

b = {x['id']:x for x in a}.values()

print(b)

आउटपुट:

[{'आयु': 34, 'आईडी': 1, 'नाम': 'जॉन'}, {'आयु': 30, 'आईडी': 2, 'नाम': 'हन्ना'}]


उसी उदाहरण में। मैं केवल समान आईडी वाले डिकेट कैसे प्राप्त कर सकता हूं?
user8162

@ user8162, क्या आप चाहते हैं कि आउटपुट जैसा दिखे?
युसुफ एक्स

कभी-कभी, मेरे पास एक ही आईडी होगी, लेकिन अलग-अलग उम्र। इसलिए आउटपुट [{'उम्र': [34, 40], 'आईडी': 1, 'नाम': ['जॉन', पीटर]}]। संक्षेप में, यदि आईडी समान हैं, तो दूसरों की सामग्री को एक सूची में संयोजित करें जैसा कि मैंने यहां बताया है। अग्रिम में धन्यवाद।
user8162

1
b = {x ['id']: [y in a if [[id '] == x [' id ']] के लिए x in a} उन्हें एक साथ समूहीकृत करने का एक तरीका है।
यूसुफ एक्स

4

जॉन ला रोय ( अजगर - अद्वितीय शब्दकोशों की सूची ) पर विस्तार करते हुए , इसे थोड़ा और लचीला बनाते हैं:

def dedup_dict_list(list_of_dicts: list, columns: list) -> list:
    return list({''.join(row[column] for column in columns): row
                for row in list_of_dicts}.values())

कॉलिंग फ़ंक्शन:

sorted_list_of_dicts = dedup_dict_list(
    unsorted_list_of_dicts, ['id', 'name'])

4

हम साथ कर सकते हैं pandas

import pandas as pd
yourdict=pd.DataFrame(L).drop_duplicates().to_dict('r')
Out[293]: [{'age': 34, 'id': 1, 'name': 'john'}, {'age': 30, 'id': 2, 'name': 'hanna'}]

नोटिस स्वीकार जवाब से थोड़ा अलग है।

drop_duplicates पंडों में सभी कॉलम की जांच करेंगे, यदि सभी समान हैं तो पंक्ति को छोड़ दिया जाएगा।

उदाहरण के लिए :

यदि हम john से peterdict तक का दूसरा नाम बदलते हैं

L=[
    {'id': 1, 'name': 'john', 'age': 34},
    {'id': 1, 'name': 'peter', 'age': 34},
    {'id': 2, 'name': 'hanna', 'age': 30},
]
pd.DataFrame(L).drop_duplicates().to_dict('r')
Out[295]: 
[{'age': 34, 'id': 1, 'name': 'john'},
 {'age': 34, 'id': 1, 'name': 'peter'},# here will still keeping the dict in the out put 
 {'age': 30, 'id': 2, 'name': 'hanna'}]

2

अजगर 3.6+ में (मैंने क्या परीक्षण किया है), बस उपयोग करें:

import json

#Toy example, but will also work for your case 
myListOfDicts = [{'a':1,'b':2},{'a':1,'b':2},{'a':1,'b':3}]
#Start by sorting each dictionary by keys
myListOfDictsSorted = [sorted(d.items()) for d in myListOfDicts]

#Using json methods with set() to get unique dict
myListOfUniqueDicts = list(map(json.loads,set(map(json.dumps, myListOfDictsSorted))))

print(myListOfUniqueDicts)

स्पष्टीकरण: हम json.dumpsशब्दकोशों को जिन्स ऑब्जेक्ट्स के रूप में एन्कोड करने के लिए मैप कर रहे हैं, जो अपरिवर्तनीय हैं। setतब अद्वितीय अपरिवर्तनीयताओं के चलने योग्य बनाने के लिए उपयोग किया जा सकता है । अंत में, हम प्रयोग करके अपने शब्दकोश प्रतिनिधित्व में वापस परिवर्तित हो जाते हैं json.loads। ध्यान दें कि शुरू में, शब्दकोशों को एक अनूठे रूप में व्यवस्थित करने के लिए कुंजी द्वारा छाँटना चाहिए। यह पायथन 3.6+ के लिए मान्य है क्योंकि डिफॉल्ट रूप से डिक्शनरी का आदेश दिया जाता है।


1
JSON डंप करने से पहले कुंजियों को क्रमबद्ध करना याद रखें। तुम भी करने से listपहले बदलने की जरूरत नहीं है set
नाथन

2

मैंने अपने पसंदीदा को बाहर निकालने की कोशिश की है:

https://repl.it/@SmaMa/Python-List-of-unique-dictionaries

# ----------------------------------------------
# Setup
# ----------------------------------------------

myList = [
  {"id":"1", "lala": "value_1"},
  {"id": "2", "lala": "value_2"}, 
  {"id": "2", "lala": "value_2"}, 
  {"id": "3", "lala": "value_3"}
]
print("myList:", myList)

# -----------------------------------------------
# Option 1 if objects has an unique identifier
# -----------------------------------------------

myUniqueList = list({myObject['id']:myObject for myObject in myList}.values())
print("myUniqueList:", myUniqueList)

# -----------------------------------------------
# Option 2 if uniquely identified by whole object
# -----------------------------------------------

myUniqueSet = [dict(s) for s in set(frozenset(myObject.items()) for myObject in myList)]
print("myUniqueSet:", myUniqueSet)

# -----------------------------------------------
# Option 3 for hashable objects (not dicts)
# -----------------------------------------------

myHashableObjects = list(set(["1", "2", "2", "3"]))
print("myHashAbleList:", myHashableObjects)

1

एक त्वरित और गंदा समाधान सिर्फ एक नई सूची तैयार करके है।

sortedlist = []

for item in listwhichneedssorting:
    if item not in sortedlist:
        sortedlist.append(item)

1

मैं नहीं जानता कि क्या आप केवल सूची में अपने dicts की आईडी अद्वितीय होना चाहते हैं, लेकिन अगर लक्ष्य के लिए तानाशाही का एक सेट है जहाँ एकता सभी कुंजियों के मूल्यों पर है .. तो आपको इस तरह से ट्यूपल कुंजी का उपयोग करना चाहिए आपकी समझ में:

>>> L=[
...     {'id':1,'name':'john', 'age':34},
...    {'id':1,'name':'john', 'age':34}, 
...    {'id':2,'name':'hanna', 'age':30},
...    {'id':2,'name':'hanna', 'age':50}
...    ]
>>> len(L)
4
>>> L=list({(v['id'], v['age'], v['name']):v for v in L}.values())
>>>L
[{'id': 1, 'name': 'john', 'age': 34}, {'id': 2, 'name': 'hanna', 'age': 30}, {'id': 2, 'name': 'hanna', 'age': 50}]
>>>len(L)
3

आशा है कि यह आपकी या किसी अन्य व्यक्ति की चिंता करने में मदद करता है ...।


1

यहाँ बहुत सारे उत्तर हैं, इसलिए मुझे एक और जोड़ना चाहिए:

import json
from typing import List

def dedup_dicts(items: List[dict]):
    dedupped = [ json.loads(i) for i in set(json.dumps(item, sort_keys=True) for item in items)]
    return dedupped

items = [
    {'id': 1, 'name': 'john', 'age': 34},
    {'id': 1, 'name': 'john', 'age': 34},
    {'id': 2, 'name': 'hanna', 'age': 30},
]
dedup_dicts(items)

0

सुंदर सीधा विकल्प:

L = [
    {'id':1,'name':'john', 'age':34},
    {'id':1,'name':'john', 'age':34},
    {'id':2,'name':'hanna', 'age':30},
    ]


D = dict()
for l in L: D[l['id']] = l
output = list(D.values())
print output

0

वैसे यहाँ वर्णित सभी उत्तर अच्छे हैं, लेकिन कुछ उत्तरों में त्रुटि का सामना करना पड़ सकता है यदि शब्दकोश आइटम में नेस्टेड सूची या शब्दकोश है, इसलिए मैं सरल उत्तर का प्रस्ताव देता हूं

a = [str(i) for i in a]
a = list(set(a))
a = [eval(i) for i in a]

-1

बाकी की तरह कॉम्पैक्ट नहीं होने की कीमत पर थोड़ा मेमोरी ओवरहेड के साथ एक कार्यान्वयन।

values = [ {'id':2,'name':'hanna', 'age':30},
           {'id':1,'name':'john', 'age':34},
           {'id':1,'name':'john', 'age':34},
           {'id':2,'name':'hanna', 'age':30},
           {'id':1,'name':'john', 'age':34},]
count = {}
index = 0
while index < len(values):
    if values[index]['id'] in count:
        del values[index]
    else:
        count[values[index]['id']] = 1
        index += 1

उत्पादन:

[{'age': 30, 'id': 2, 'name': 'hanna'}, {'age': 34, 'id': 1, 'name': 'john'}]

1
आपको इसे थोड़ा और परखने की जरूरत है। इस सूची को संशोधित करते हुए जब आप इस पर पुनरावृत्ति कर रहे हों तो यह हमेशा आपकी अपेक्षा के
अनुरूप

@gnibbler बहुत अच्छा बिंदु! मैं उत्तर हटा दूँगा और इसे और अच्छी तरह से परखूँगा।
सामी वेलर

बेहतर लग रहा है। आप डिक्‍ट की जगह आईडी का ट्रैक रखने के लिए सेट का उपयोग कर सकते हैं। पर शुरू करने और पीछे की ओर गिनने indexपर विचार करें len(values), इसका मतलब है कि आप हमेशा indexयह समझ सकते हैं कि आप delया नहीं। जैसेfor index in reversed(range(len(values))):
जॉन ला रोय

@gnibbler दिलचस्प है, सेट लगातार शब्दकोशों की तरह लग रहे हो?
सामी वेलर

-4

यह समाधान है जो मैंने पाया:

usedID = []

x = [
{'id':1,'name':'john', 'age':34},
{'id':1,'name':'john', 'age':34},
{'id':2,'name':'hanna', 'age':30},
]

for each in x:
    if each['id'] in usedID:
        x.remove(each)
    else:
        usedID.append(each['id'])

print x

मूल रूप से आप यह जाँचते हैं कि आईडी सूची में मौजूद है या नहीं, यदि है तो डिक्शनरी को हटा दें, यदि नहीं, तो सूची में आईडी संलग्न करें


मैं यूडीआईडी ​​के लिए सूची के बजाय एक सेट का उपयोग करूंगा। यह तेजी से लुकअप है, और अधिक पठनीय है
Happyydave

हाँ, मैं सेट्स के बारे में नहीं जानता ... लेकिन मैं सीख रहा हूँ ... मैं सिर्फ @gnibbler जवाब देख रहा था ...
tabchas

1
आपको इसे थोड़ा और परीक्षण करने की आवश्यकता है। सूची को संशोधित करते हुए जब आप इस पर पुनरावृत्ति कर रहे हों तो यह हमेशा आपकी अपेक्षा के
अनुरूप

हाँ, मुझे समझ में नहीं आता कि यह काम क्यों नहीं करता है ... कोई भी विचार जो मैं गलत कर रहा हूं?
tabchas

नहीं, मैंने इस समस्या को पकड़ लिया है ... इसका मतलब यह है कि मुझे समझ में नहीं आता कि इसकी समस्या क्यों दे रही है ... क्या आप जानते हैं?
टैब
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.