2012-03-28 14 views
12

मैं किसी सूची में 0 या अधिक dicts है:अजगर: कई dicts की केवल आम कुंजी-मान जोड़ों पाते हैं: dict चौराहे

>>> dicts = [dict(a=3, b=89, d=2), dict(a=3, b=89, c=99), dict(a=3, b=42, c=33)] 

मैं एक नया dict कि केवल चाबियाँ कि में होते हैं बनाना चाहते हैं सभी ऊपर dicts और वह भी तब मान हैं सभी एक ही:

>>> dict_intersection(*dicts) 
{"a": 3} 

मुझे लगता है कि वहाँ एक सुरुचिपूर्णdict_intersection लेखन के माध्यम से किया जाना चाहिए, लेकिन मैं केवल असजीला के साथ आ रहा हूँ और/या ऑफ़लाइन खुद को फायदेमंद समाधान। सुझाव?

+0

आप अपने उदाहरण में स्ट्रिंग शाब्दिक उद्धरण भूल गया। ;) दिलचस्प सवाल - मैं इस पर ध्यान और वापसी करूंगा। –

+1

और निश्चित रूप से, आप अब तक किस तरह से आए हैं? – hochl

+0

@ ली-औंग: कक्षा के समान 'dict' को instanciating जब स्ट्रिंग शाब्दिक उद्धरण की आवश्यकता नहीं है। मुझे उन अजीब उद्धरणों से बचने के लिए यह एक बहुत ही आसान शॉर्टकट मिलता है। –

उत्तर

18
>>> dict(set.intersection(*(set(d.iteritems()) for d in dicts))) 
{'a': 3} 

नोट: इस समाधान के लिए चाबियों के अतिरिक्त, शब्दकोश मानों को हेशेबल होने की आवश्यकता है।

+1

हान ... मुझे इसे हराया ... – jamylak

+0

ठीक है, आपने मुझे हराया है। एक बार फिर यह साबित कर रहा है कि एक सेट छेड़छाड़ ऑपरेशन 'सेट' संचालन का उपयोग करके सबसे अच्छा प्रदर्शन किया जाता है।) –

1

थोड़ा और हाथ-गंदे दृष्टिकोण: प्रत्येक शब्दकोश के लिए कुंजी की सूची लें, प्रत्येक सूची को क्रमबद्ध करें, और फिर आगे बढ़ें जैसे कि आप उन्हें विलय कर रहे थे (प्रत्येक सूची के लिए एक सूचकांक रखें, एक w/सबसे कम मूल्य अग्रिम करें)। जब भी सभी सूचकांक एक ही कुंजी पर इंगित करते हैं, समानता के लिए मूल्यों की जांच करें; किसी भी तरह से, सभी सूचकांक अग्रिम।

+0

संकल्पनात्मक रूप से सुरुचिपूर्ण, लेकिन सॉर्टिंग ऐसा लगता है कि यह महंगा होगा। ऐसा लगता है कि आपको बहुत सारे "नलसाजी" कोड की आवश्यकता होगी (हालांकि 'itertools' का न्यायसंगत उपयोग मदद कर सकता है।) –

3
>>> dicts 
[{'a': 3, 'b': 89, 'd': 2}, {'a': 3, 'c': 99, 'b': 89}, {'a': 3, 'c': 33, 'b': 42}] 
>>> sets = (set(d.iteritems()) for d in dicts) 
>>> dict_intersection = dict(set.intersection(*sets)) 
>>> dict_intersection 
{'a': 3} 
4

चूंकि कुंजी/मूल्य जोड़े पहले ही पहले ही हो चुके हैं, तो आप इस निर्देश के आइटमों को फिर से शुरू कर सकते हैं।

dict(pair for pair in dicts[0].items() 
    if all((pair in d.items() for d in dicts[1:]))) 

इंटरजे के उत्तर से कम सुरुचिपूर्ण लग रहा है, लेकिन हैशबल मानों के प्रतिबंध के बिना काम करता है।

संपादित करें: गति सुधार

+0

+1 मुझे लगता है कि यह बहुत ही सुरुचिपूर्ण है क्योंकि यह गैर-हैशबल के लिए काम करता है। – hochl

+0

@jamylak dict की सूची के मामले में इसका उपयोग कैसे किया जा सकता है जहां मान गैर-अक्षम हैं। उपर्युक्त व्यक्ति केवल पहले नियम और सूची में अन्य निर्देशों में सामान्य वस्तुओं को खोजने के लिए काम करता है। – learnningprogramming

3

इस कैसा है के लिए एक जनरेटर अभिव्यक्ति को all अभिव्यक्ति बदल गया है?

def intersect_two_dicts (d1, d2): 
    return { k:v for k,v in d1.iteritems() if ((k in d2)and(d1[k]==d2[k])) } 

def intersect_dicts (list_of_dicts): 
    return reduce(intersect_two_dicts, list_of_dicts) 

# Tests 
dicts = [dict(a=3, b=89, d=2), dict(a=3, b=89, c=99), dict(a=3, b=42, c=33)] 
print (intersect_two_dicts(dicts[0], dicts[1])) 
print (intersect_dicts(dicts)) 

संपादित करें (1): मुझे यकीन नहीं है कि इनमें से कौन सा सबसे तेज़ है। set.intersection समाधान निश्चित रूप से सबसे अधिक सुरुचिपूर्ण (लघु एक लाइनर हैं!) लेकिन मुझे कुछ बेंचमार्किंग देखने में दिलचस्पी होगी।

संपादित करें (2): -: दो किसी भी शब्दकोश में (मूल्य कुंजी) जोड़े आम हैं: बोनस किसी भी प्रविष्टियों जिसका शब्दकोश मिल

{k:count for k,count in 
collections.Counter(itertools.chain(*[d.iteritems() for d in dicts])).iteritems() 
if count > 1} 
+0

यह कहता है कि नाम कम करने के लिए – learnningprogramming

+1

@learnningprogramming परिभाषित नहीं किया गया है यदि आप पाइथन 3 का उपयोग कर रहे हैं, 'कम करें() 'अब' आयात functools', 'functools.reduce()' है। –

संबंधित मुद्दे