केवल कुछ कुंजियों को शामिल करने के लिए तानाशाही को फ़िल्टर करें?


496

मुझे मिल गया है dictकि प्रविष्टियों का एक पूरा गुच्छा है। मुझे उनमें से कुछ चुनिंदा लोगों में ही दिलचस्पी है। क्या अन्य लोगों को बाहर निकालने का एक आसान तरीका है?


यह कहना उपयोगी है कि किस प्रकार की चाबियाँ (पूर्णांक? स्ट्रिंग? तिथियां? मनमानी वस्तुएं?) और इस प्रकार कि क्या चाबियाँ हैं या बाहर की जाँच करने के लिए एक सरल (स्ट्रिंग, regex, सूची सदस्यता, या संख्यात्मक असमानता) परीक्षण है। या फिर हमें यह निर्धारित करने के लिए एक मनमाना फ़ंक्शन (ओं) को कॉल करने की आवश्यकता है।
23

@smci स्ट्रिंग कुंजी। ऐसा मत सोचो कि यह मेरे साथ भी हुआ है कि मैं कुछ और भी इस्तेमाल कर सकता हूं; मैं जेएस और पीएचपी में इतने लंबे समय से कोडिंग कर रहा हूं ...
एमपीएन

जवाबों:


654

एक नए तानाशाह का निर्माण:

dict_you_want = { your_key: old_dict[your_key] for your_key in your_keys }

शब्दकोश समझ का उपयोग करता है।

यदि आप एक ऐसे संस्करण का उपयोग करते हैं, जिसमें उनकी कमी है (अर्थात पायथन 2.6 और पूर्व में), तो इसे बनाएं dict((your_key, old_dict[your_key]) for ...)। यह वही है, हालांकि बदसूरत है।

ध्यान दें कि यह, jnnnnn के संस्करण के विपरीत, old_dictकिसी भी आकार के लिए स्थिर प्रदर्शन (केवल आपके_की संख्या पर निर्भर करता है) है । गति और स्मृति दोनों के संदर्भ में। चूंकि यह एक जनरेटर अभिव्यक्ति है, यह एक समय में एक आइटम को संसाधित करता है, और यह old_dict के सभी आइटमों के माध्यम से नहीं दिखता है।

जगह में सब कुछ हटाना:

unwanted = set(keys) - set(your_dict)
for unwanted_key in unwanted: del your_dict[unwanted_key]

8
"डिक्शनरी कॉम्प्रिहेंशन का उपयोग करता है, यदि आप किसी ऐसे संस्करण का उपयोग करते हैं, जिसमें उनकी कमी है" == संस्करण <= 2.6
गेटेखा

8
यदि कोई फ़ीलर कुंजियाँ Old_dict में मौजूद नहीं हैं, तो KeyError फेंकता है। मैं {k: d [k] फ़िल्टर में k के लिए यदि k में d} का सुझाव
दूंगा

1
@PeterGibson हाँ, यदि यह आवश्यकताओं का हिस्सा है, तो आपको इसके बारे में कुछ करने की आवश्यकता है। चाहे वह चुपचाप चाबियाँ छोड़ रहा हो, डिफ़ॉल्ट मान या कुछ और जोड़ रहा हो, इस पर निर्भर करता है कि आप क्या कर रहे हैं; ऐसे बहुत से उपयोग मामले हैं जहां आपका दृष्टिकोण गलत है। कई ऐसे भी हैं जहां एक कुंजी old_dictकहीं और बग को इंगित करने के लिए गायब है, और उस स्थिति में मैं चुपचाप गलत परिणामों के लिए एक त्रुटि पसंद करता हूं।

@delnan, "if k in d" के अलावा आपको धीमा कर देता है यदि d बड़ा है, तो मुझे लगा कि यह ध्यान देने योग्य है
पीटर गिब्सन

7
@PeterGibson यह नहीं है, शब्दकोश खोज O (1) है।

130

थोड़ा और अधिक सुरुचिपूर्ण तानाशाही:

foodict = {k: v for k, v in mydict.items() if k.startswith('foo')}

Upvoted। मैं इसी से मिलता-जुलता जवाब जोड़ने के बारे में सोच रहा था। हालांकि जिज्ञासा से बाहर, क्यों {k: v for k, v में तानाशाही () ...} के बजाय {k: तानाशाह [k] के लिए तानाशाही में ...} क्या कोई प्रदर्शन अंतर है?
हार्ट सिम्हा

4
मेरे ही सवाल का जवाब दिया। {K: तानाशाह [k] के लिए k में तानाशाह ...} लगभग 20-25% तेज है, कम से कम पायथन 2.7.6 में, 26 आइटम्स (timeit (..., setup = "d =) के शब्दकोश के साथ। {chr (x + 97): x + 1 में x के लिए रेंज (26)} ")), कितने आइटम फ़िल्टर किए जा रहे हैं, इस पर निर्भर करता है (व्यंजन कुंजियों को फ़िल्टर करना, स्वर कुंजियों को फ़िल्टर करने की तुलना में तेज़ है क्योंकि आप ऊपर देख रहे हैं कम आइटम)। आपके शब्दकोश का आकार बढ़ने पर प्रदर्शन में अंतर बहुत कम हो सकता है।
हार्ट सिम्हा

5
यदि आप mydict.iteritems()इसके बजाय इस्तेमाल करते हैं तो शायद वही सिद्ध होगा । .items()एक और सूची बनाता है।
पैट

64

यहाँ अजगर 2.6 में एक उदाहरण है:

>>> a = {1:1, 2:2, 3:3}
>>> dict((key,value) for key, value in a.iteritems() if key == 1)
{1: 1}

फ़िल्टरिंग भाग ifकथन है।

यह विधि डेलान के उत्तर की तुलना में धीमी है यदि आप केवल बहुत सी चाबियों में से कुछ का चयन करना चाहते हैं।


11
सिवाय इसके कि मैं शायद if key in ('x','y','z')अनुमान लगाता हूँ।
एमपैन

यदि आप पहले से जानते हैं कि आपको कौन सी कुंजी चाहिए, तो डेलान के उत्तर का उपयोग करें। यदि आपको एक कथन के साथ प्रत्येक कुंजी का परीक्षण करने की आवश्यकता है, तो रैंसफोर्ड के उत्तर का उपयोग करें।
jnnnnn

1
इस समाधान का एक और फायदा है। यदि डिक्शनरी एक महंगे फंक्शन कॉल से वापस आ जाती है (यानी a / old_dict एक फंक्शन कॉल है) तो यह सॉल्यूशन केवल एक बार फंक्शन को कॉल करता है। एक चर में फ़ंक्शन द्वारा लौटाए जाने वाले अनिवार्य वातावरण में एक बड़ा सौदा नहीं है, लेकिन एक कार्यात्मक वातावरण में (उदाहरण के लिए एक लैम्ब्डा में) यह महत्वपूर्ण अवलोकन है।
Gae123


20

कोड 1:

dict = { key: key * 10 for key in range(0, 100) }
d1 = {}
for key, value in dict.items():
    if key % 2 == 0:
        d1[key] = value

कोड 2:

dict = { key: key * 10 for key in range(0, 100) }
d2 = {key: value for key, value in dict.items() if key % 2 == 0}

कोड 3:

dict = { key: key * 10 for key in range(0, 100) }
d3 = { key: dict[key] for key in dict.keys() if key % 2 == 0}

कोड प्रदर्शन के सभी pieced को संख्या = 1000 का उपयोग करके समयसीमा के साथ मापा जाता है, और कोड के प्रत्येक टुकड़े के लिए 1000 बार एकत्र किया जाता है।

यहाँ छवि विवरण दर्ज करें

अजगर 3.6 के लिए फिल्टर हुक कुंजी के तीन तरीकों का प्रदर्शन लगभग समान है। अजगर के लिए 2.7 कोड 3 थोड़ा तेज है।


बस जिज्ञासु, क्या तुमने पायथन से उस साजिश को बनाया?
user5359531

1
आर में ggplot2 - का हिस्सा tidyverse
keithpjolley

18

यह एक लाइनर लैम्बडा काम करना चाहिए:

dictfilt = lambda x, y: dict([ (i,x[i]) for i in x if i in set(y) ])

यहाँ एक उदाहरण है:

my_dict = {"a":1,"b":2,"c":3,"d":4}
wanted_keys = ("c","d")

# run it
In [10]: dictfilt(my_dict, wanted_keys)
Out[10]: {'c': 3, 'd': 4}

यह एक मूल सूची है जो आपकी तानाशाही कुंजी (i x) पर निर्भर करती है और यदि आपकी इच्छित कुंजी सूची (y) में रहती है तो tuple (कुंजी, मान) जोड़े की सूची को आउटपुट करती है। एक तानाशाह () पूरी चीज को आउटपुट के रूप में लपेटता है।


के setलिए उपयोग करना चाहिए wanted_keys, लेकिन अन्यथा अच्छा लग रहा है।
एमपीएन

यह मुझे एक रिक्त शब्दकोश देता है यदि मेरे मूल शब्दकोश में मूल्यों के स्थान पर सूचियाँ हैं। किसी भी काम?
फ़ॉफ़ी

@Francesco, क्या आप एक उदाहरण प्रदान कर सकते हैं? अगर मैं दौड़ता हूं: dictfilt({'x':['wefwef',52],'y':['iuefiuef','efefij'],'z':['oiejf','iejf']}, ('x','z'))तो यह {'x': ['wefwef', 52], 'z': ['oiejf', 'iejf']}इरादा के अनुसार लौटता है ।
जिम

मैंने इसके साथ प्रयास किया: dict={'0':[1,3], '1':[0,2,4], '2':[1,4]}और परिणाम यह था {}, जिसे मैंने एक रिक्त तानाशाही माना।
फ़ॉफ़ी

एक बात, "तानाशाही" एक आरक्षित शब्द है, इसलिए आपको इसका उपयोग किसी तानाशाह का नाम लेने के लिए नहीं करना चाहिए। वे कौन सी चाबियां थीं जिन्हें आप बाहर निकालने की कोशिश कर रहे थे अगर मैं दौड़ता हूं: foo = {'0':[1,3], '1':[0,2,4], '2':[1,4]}; dictfilt(foo,('0','2'))मुझे मिलता है: {'0': [1, 3], '2': [1, 4]}जो अभीष्ट परिणाम है
जिम

14

आपके मूल शब्दकोश origऔर प्रविष्टियों के सेट को देखते हुए, जिनमें आप रुचि रखते हैं keys:

filtered = dict(zip(keys, [orig[k] for k in keys]))

जो डेलान के उत्तर के रूप में अच्छा नहीं है, लेकिन ब्याज के हर पायथन संस्करण में काम करना चाहिए। हालांकि, यह keysआपके मूल शब्दकोश में मौजूदा के प्रत्येक तत्व के लिए नाजुक है ।


खैर, यह मूल रूप से मेरी तानाशाही समझ के "ट्यूपल जनरेटर संस्करण" का एक उत्सुक संस्करण है। बहुत संगत वास्तव में, हालांकि जनरेटर अभिव्यक्तियों को 2.4, वसंत 2005 में पेश किया गया था - गंभीरता से, क्या कोई अभी भी इसका उपयोग कर रहा है?

1
मैं असहमत नहीं हूं; 2.3 वास्तव में अब मौजूद नहीं होना चाहिए। हालाँकि, 2.3 उपयोग के एक पुराने सर्वेक्षण के रूप में: moinmo.in/PollAboutRequiringPython24 लघु संस्करण: RHEL4, SLES9, OS X 10.4 के साथ भेज दिया गया
काई

7

डेलान द्वारा स्वीकार किए गए उत्तर के आधार पर।

क्या होगा यदि आपकी एक वांछित कुंजी Old_dict में नहीं है? डेलान समाधान एक KeyError अपवाद को फेंक देगा जिसे आप पकड़ सकते हैं। यदि ऐसा नहीं है जो आपको चाहिए तो शायद आप चाहते हैं:

  1. केवल उन कुंजियों को शामिल करें जो पुराने_दोनों में और आपके चाहने वालों के समूह को उत्तेजित करती हैं।

    old_dict = {'name':"Foobar", 'baz':42}
    wanted_keys = ['name', 'age']
    new_dict = {k: old_dict[k] for k in set(wanted_keys) & set(old_dict.keys())}
    
    >>> new_dict
    {'name': 'Foobar'}
  2. उन कुंजियों के लिए एक डिफ़ॉल्ट मान है जो पुराने_डिक्ट में सेट नहीं हैं।

    default = None
    new_dict = {k: old_dict[k] if k in old_dict else default for k in wanted_keys}
    
    >>> new_dict
    {'age': None, 'name': 'Foobar'}

आप यह भी कर सकते हैं{k: old_dict.get(k, default) for k in ...}
Moberg

6

यह कार्य करेगा चाल:

def include_keys(dictionary, keys):
    """Filters a dict by only including certain keys."""
    key_set = set(keys) & set(dictionary.keys())
    return {key: dictionary[key] for key in key_set}

डेलान के संस्करण की तरह, यह एक शब्दकोश समझ का उपयोग करता है और इसमें बड़े शब्दकोशों के लिए स्थिर प्रदर्शन होता है (केवल आपके द्वारा अनुमत कुंजी की संख्या पर निर्भर करता है, और शब्दकोश में कुंजियों की कुल संख्या नहीं)।

और MyGGan के संस्करण की तरह, यह आपकी कुंजी को सूची में शामिल करने की अनुमति देता है जो कि शब्दकोश में मौजूद नहीं हो सकता है।

और एक बोनस के रूप में, यहाँ उलटा है, जहाँ आप मूल में कुछ कुंजियों को छोड़कर एक शब्दकोश बना सकते हैं:

def exclude_keys(dictionary, keys):
    """Filters a dict by excluding certain keys."""
    key_set = set(dictionary.keys()) - set(keys)
    return {key: dictionary[key] for key in key_set}

ध्यान दें कि डेलन के संस्करण के विपरीत, ऑपरेशन जगह में नहीं किया गया है, इसलिए प्रदर्शन शब्दकोश में कुंजी की संख्या से संबंधित है। हालांकि, इसका लाभ यह है कि फ़ंक्शन प्रदान किए गए शब्दकोश को संशोधित नहीं करेगा।

संपादित करें: कुछ कुंजियों को एक तानाशाह से बाहर करने के लिए एक अलग फ़ंक्शन जोड़ा गया।


आपको keysकिसी भी प्रकार की पुनरावृत्ति की अनुमति देनी चाहिए , जैसे कि कौन सा सेट स्वीकार करता है।
एमपीन

आह, अच्छी कॉल, यह इंगित करने के लिए धन्यवाद। मैं उस अद्यतन कर दूँगा।
रयान

मुझे आश्चर्य है कि अगर आप दो कार्यों के साथ बेहतर हैं। यदि आप 10 लोगों से पूछते हैं "क्या invertइसका मतलब यह है कि keysतर्क रखा जाता है, या यह keysतर्क खारिज कर दिया जाता है?", उनमें से कितने सहमत होंगे?
स्केटनर

अपडेट किया गया। आप क्या सोचते हैं मुझे बताओ।
रयान

ऐसा प्रतीत होता है कि इनपुट कमांड में मूल्यों के स्थान पर सूचियाँ हैं तो यह काम नहीं करता है। इस मामले में आपको एक शून्य ताना मिलता है। किसी भी काम?
फ़ॉफ़ी

4

यदि हम हटाए गए चयनित कुंजी के साथ एक नया शब्दकोश बनाना चाहते हैं, तो हम
उदाहरण के लिए शब्दकोश समझ का उपयोग कर सकते हैं :

d = {
'a' : 1,
'b' : 2,
'c' : 3
}
x = {key:d[key] for key in d.keys() - {'c', 'e'}} # Python 3
y = {key:d[key] for key in set(d.keys()) - {'c', 'e'}} # Python 2.*
# x is {'a': 1, 'b': 2}
# y is {'a': 1, 'b': 2}

साफ। केवल पायथन 3 में काम करता है। पायथन 2 का कहना है कि "TypeError: unsupported operand type (s) for -: 'लिस्ट' और 'सेट'"
MPen

जोड़ा गया (d.keys ()) पायथन 2 के लिए। यह मेरे चलने पर काम कर रहा है।
श्रीवास्तव

2

एक अन्य विकल्प:

content = dict(k1='foo', k2='nope', k3='bar')
selection = ['k1', 'k3']
filtered = filter(lambda i: i[0] in selection, content.items())

लेकिन आपको एक list(पायथन 2) या एक पुनरावृत्ति करने वाला (पायथन 3) मिलता है filter(), नहीं dict


लपेटें filteredमें dictऔर आप शब्दकोश वापस मिल!
CMCDragonkai

1

संक्षिप्त रूप:

[s.pop(k) for k in list(s.keys()) if k not in keep]

जैसा कि ज्यादातर जवाबों में सुझाव दिया गया है कि सुगमता बनाए रखने के लिए हमें डुप्लिकेट ऑब्जेक्ट बनाना होगा listया यह होना चाहिए dict। यह एक फेंक-दूर बनाता है listलेकिन मूल में कुंजियों को हटा देता है dict


0

यहाँ delएक लाइनर का उपयोग करते हुए एक और सरल विधि है :

for key in e_keys: del your_dict[key]

e_keysबाहर रखी जाने वाली चाबियों की सूची है। यह आपको एक नया देने के बजाय आपके आदेश को अद्यतन करेगा।

यदि आप एक नया आउटपुट तानाशाही चाहते हैं, तो हटाने से पहले तानाशाह की एक प्रति बनाएं:

new_dict = your_dict.copy()           #Making copy of dict

for key in e_keys: del new_dict[key]

0

आप उपयोग कर सकते हैं python-benedict, यह एक तानाशाही उपवर्ग है।

स्थापना: pip install python-benedict

from benedict import benedict

dict_you_want = benedict(your_dict).subset(keys=['firstname', 'lastname', 'email'])

यह GitHub पर खुला-स्रोत है: https://github.com/fabiocaccamo/python-benedict


अस्वीकरण: मैं इस पुस्तकालय का लेखक हूं।

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