इस पर पुनरावृत्ति करते हुए किसी शब्दकोश से आइटम कैसे हटाएं?


295

क्या पायथन में एक शब्दकोश से आइटम हटाना वैध है, जबकि उस पर चलने के लिए?

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

for k, v in mydict.iteritems():
   if k == val:
     del mydict[k]

यह विचार उन तत्वों को हटाने का है, जो शब्दकोश से एक निश्चित स्थिति को पूरा नहीं करते हैं, इसके बजाय एक नया शब्दकोश बनाने के लिए जो एक से अधिक होने का सबसेट है।

क्या यह एक अच्छा उपाय है? क्या अधिक सुरुचिपूर्ण / कुशल तरीके हैं?


1
बहुत दिलचस्प जवाब के साथ एक संबंधित प्रश्न: stackoverflow.com/questions/9023078/…
अधिकतम

कोई भी आसानी से कोशिश कर सकता था। यदि यह विफल रहता है, तो यह वैध नहीं है।
त्रिशूल

26
@ ट्रिलियनियन वन आसानी से कोशिश कर सकता था ... और आसानी से मूल्य का कुछ भी नहीं सीखा। यदि यह सफल होता है, तो जरूरी नहीं कि यह वैध हो। बढ़त के मामले और अप्रत्याशित कैवेट लाजिमी है। यह प्रश्न सभी के लिए गैर-तुच्छ अभिरुचि का होगा-पाइथोनिस्टस का। "एक आसानी से कोशिश कर सकता था" के आदेश पर हाथ लहराते हुए बर्खास्तगी! stackoverflow जांच के जिज्ञासु भावना के विपरीत अनपेक्षित और विपरीत है।
सेसिल करी

ध्यानपूर्वक पढ़ने के बाद अधिकतम 's संबंधित सवाल , मैं सहमत होना आवश्यक है। आप शायद केवल उस गड़बड़ी को गहराई से पूछना चाहते हैं और इसके बजाय इसके लिखित उत्तर देना चाहते हैं। आपका पायथोनिक दिमाग उड़ जाएगा।
सेसिल करी

1
@ CecilCurry अपने विचार प्रस्तुत करने से पहले यह प्रस्तुत करने से पहले कि मैं गलत नहीं हूँ, स्टैकओवरफ़्लो की भावना में एक प्रकार है। मैं बस यही बताना चाहता था। क्षमा करें यदि उसकी वजह से कोई गड़बड़ी हुई है। इसके अलावा, मुझे लगता है कि यह एक अच्छा सवाल है और इसे कम नहीं किया। मुझे जोहान रिट्जेल का जवाब सबसे ज्यादा पसंद है। मुझे नहीं लगता कि किसी को दूसरे चरण में हटाने पर मक्खी को हटाने के लिए वह सब करने की जरूरत होती है, जो अधिक सरल है। मेरे विचार में यह पसंदीदा तरीका होना चाहिए।
ट्रिलियन

जवाबों:


305

संपादित करें:

यह जवाब पायथन 3 के लिए काम नहीं करेगा और ए देगा RuntimeError

RuntimeError: शब्दकोश ने पुनरावृति के दौरान आकार बदल दिया।

ऐसा इसलिए होता है क्योंकि mydict.keys()एक सूची में एक पुनरावृत्त रिटर्न देता है। जैसा कि टिप्पणियों में बताया गया है कि इसके mydict.keys()द्वारा सूची में परिवर्तित list(mydict.keys())हो जाना चाहिए और इसे काम करना चाहिए।


कंसोल में एक साधारण परीक्षण से पता चलता है कि आप एक शब्दकोश को संशोधित नहीं कर सकते, जबकि इस पर ध्यान दें:

>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k, v in mydict.iteritems():
...    if k == 'two':
...        del mydict[k]
...
------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython console>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

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

>>> for k in mydict.keys():
...    if k == 'two':
...        del mydict[k]
...
>>> mydict
{'four': 4, 'three': 3, 'one': 1}

यदि आपको आइटम मान के आधार पर हटाने की आवश्यकता है, तो items()इसके बजाय विधि का उपयोग करें :

>>> for k, v in mydict.items():
...     if v == 3:
...         del mydict[k]
...
>>> mydict
{'four': 4, 'one': 1}

53
ध्यान दें कि पायथन 3 में, तानाशाही () एक पुनरावृत्त (और तानाशाही) () चला गया है।
टिम लेशर

83
@TimLesher टिप्पणी पर विस्तार से जानने के लिए ... यह पायथन 3 में काम नहीं करेगा।
अधिकतम

99
@ अधिकतम विस्तार पर विस्तार करने के लिए, यह काम करेगा यदि आप उपरोक्त कोड को 2to3 के साथ परिवर्तित करते हैं। डिफ़ॉल्ट फिक्सर में से एक लूप की तरह दिखाई देगा for k, v in list(mydict.items()):जो पायथन में ठीक काम करता है। 3. keys()बनने के लिए भी list(keys())
वाल्टर मुंड

8
यह काम नहीं करता है। मुझे एक त्रुटि मिलती है:RuntimeError: dictionary changed size during iteration
टॉम ज़ातो -

14
@ TomášZato के रूप में वाल्टर ने बताया, python3 के लिए आपको python3 के for k in list(mydict.keys()): रूप में उपयोग करने की आवश्यकता होती है, कुंजी () विधि को पुनरावृत्त बनाता है, और पुनरावृत्ति के दौरान प्रमुख वस्तुओं को हटाना भी बंद कर देता है। सूची () कॉल जोड़कर आप कुंजियों () पुनरावृत्ति को सूची में बदल देते हैं। इसलिए जब आप लूप के लिए शरीर में होते हैं, तो आप शब्दकोष पर अधिक ध्यान नहीं देते हैं।
ज्योफ क्रॉम्पटन

89

आप इसे दो चरणों में भी कर सकते हैं:

remove = [k for k in mydict if k == val]
for k in remove: del mydict[k]

मेरा पसंदीदा तरीका आमतौर पर एक नया तानाशाही करना है:

# Python 2.7 and 3.x
mydict = { k:v for k,v in mydict.items() if k!=val }
# before Python 2.7
mydict = dict((k,v) for k,v in mydict.iteritems() if k!=val)

11
@ सादर: वास्तव में 2.7 के बाद से।
जोहान रिट्जेल

5
तानाशाह की व्यापक दृष्टिकोण शब्दकोश की एक प्रति बनाता है; सौभाग्य से मूल्यों को कम से कम गहराई से कॉपी नहीं किया जाता है, बस जुड़ा हुआ है। फिर भी अगर आपके पास बहुत सी चाबियां हैं, तो यह खराब हो सकती है। उस कारण से, मुझे removeलूप अप्रोच अधिक पसंद है।
अधिकतम

1
आप चरणों को भी जोड़ सकते हैं:for k in [k for k in mydict if k == val]: del mydict[k]
AXO

पहला समाधान इस थ्रेड में अब तक बड़े डक्ट्स पर एकमात्र कुशल है - क्योंकि यह पूरी लंबाई की प्रतिलिपि नहीं बनाता है।
kxr

21

आप इसे संग्रहित करते समय संग्रह को संशोधित नहीं कर सकते। इस तरह से पागलपन होता है - सबसे विशेष रूप से, यदि आपको वर्तमान आइटम को हटाने और हटाने की अनुमति दी गई है, तो इट्रेटर को (+1) पर चलना होगा और अगली कॉल nextआपको (+2) से परे ले जाएगी, इसलिए आप अंत एक तत्व लंघन (आप हटाए गए एक के पीछे एक सही)। आपके पास दो विकल्प हैं:

  • सभी कुंजी (या मान, या दोनों, जो आपको चाहिए) के आधार पर कॉपी करें, फिर उन पर पुनरावृति करें। आप इसके लिए .keys()एट अल का उपयोग कर सकते हैं (पायथन 3 में, परिणामी पुनरावृत्ति पास करें list)। हालांकि अत्यधिक व्यर्थ स्थान-वार हो सकता है।
  • दोहराएं से अधिक mydictहमेशा की तरह, कुंजी बचत एक अलग संग्रह में हटाने के लिए to_delete। जब आप पुनरावृत्ति कर रहे हों mydict, तो सभी आइटम को इसमें to_deleteसे हटा दें mydict। पहले दृष्टिकोण पर कुछ को बचाता है (कितनी कुंजियों को हटा दिया जाता है और कितने ठहरने पर निर्भर करता है), लेकिन इसके लिए कुछ और लाइनों की भी आवश्यकता होती है।

You can't modify a collection while iterating it.यह केवल डिकेट्स और दोस्तों के लिए सही है, लेकिन आप पुनरावृत्ति के दौरान सूचियों को संशोधित कर सकते हैं:L = [1,2,None,4,5] <\n> for n,x in enumerate(L): <\n\t> if x is None: del L[n]
निल्स लिंडमैन

3
@ नील यह एक अपवाद नहीं है, लेकिन यह अभी भी गलत है। निरीक्षण करें: codepad.org/Yz7rjDVT - स्पष्टीकरण के लिए देखें stackoverflow.com/q/6260089/395760

मुझे यहाँ ले आया। अभी भी can'tकेवल तानाशाह और दोस्तों के लिए सही है, जबकि यह shouldn'tसूचियों के लिए होना चाहिए ।
निल्स लिंडमैन

20

इसके बजाय एक प्रति पर Iterate, जैसे कि एक ने लौटाया items():

for k, v in list(mydict.items()):

1
इसका कोई मतलब नहीं है - फिर आप del vसीधे नहीं कर सकते हैं, इसलिए आपने प्रत्येक वी की एक प्रति बनाई है जिसका आप कभी उपयोग नहीं करने वाले हैं और आपको किसी भी तरह से आइटम का उपयोग करना होगा। dict.keys()एक बेहतर विकल्प है।
jscs

2
@ जोश: यह सब इस बात पर निर्भर करता है कि आपको vविलोपन की कसौटी के रूप में कितना उपयोग करने की आवश्यकता है ।
इग्नासियो वाज़क्वेज़-अब्राम्स

3
पायथन 3 के तहत, dict.items()एक कॉपी के बजाय एक पुनरावृत्त लौटाता है। ब्लेयर के उत्तर के लिए टिप्पणी देखें , जो (दुख की बात है) पायथन 2 शब्दार्थ को भी मानता है।
सेसिल करी

10

यह उपयोग करने के लिए सबसे साफ है list(mydict):

>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k in list(mydict):
...     if k == 'three':
...         del mydict[k]
... 
>>> mydict
{'four': 4, 'two': 2, 'one': 1}

यह सूचियों के समानांतर संरचना से मेल खाती है:

>>> mylist = ['one', 'two', 'three', 'four']
>>> for k in list(mylist):                            # or mylist[:]
...     if k == 'three':
...         mylist.remove(k)
... 
>>> mylist
['one', 'two', 'four']

दोनों python2 और python3 में काम करते हैं।


यदि आपका डेटासेट बड़ा है तो यह अच्छा नहीं है। यह स्मृति में सभी वस्तुओं को कॉपी कर रहा है, है ना?
AFP_555

1
@ AFP_555 हां - मेरा लक्ष्य यहां स्वच्छ, समानांतर, पाइथोनिक कोड के लिए है। यदि आपको मेमोरी दक्षता की आवश्यकता है, तो मुझे पता है कि सबसे अच्छा तरीका यह है कि इसे हटाना या हटाने के लिए कुंजी की एक सूची बनाना या सहेजने के लिए आइटम का एक नया तानाशाही। पायथन के साथ सौंदर्य मेरी प्राथमिकता है; बड़े डेटासेट के लिए मैं Go या Rust का उपयोग कर रहा हूं।
rsanden

9

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

d = {k:d[k] for k in d if d[k] != val}


यह सबसे पाइथोनिक है।
येहोसफ

लेकिन यह जगह में संशोधन करने के बजाय एक नया शब्दकोश बनाता dहै।
एरिस्टाइड

9

Python3 के साथ, dic.keys () पर पुनरावृति शब्दकोश आकार त्रुटि को बढ़ाएगा। आप इस वैकल्पिक तरीके का उपयोग कर सकते हैं:

Python3 के साथ परीक्षण किया गया है, यह ठीक काम करता है और त्रुटि " पुनरावृति के दौरान परिवर्तित आकार " शब्द नहीं उठाया गया है:

my_dic = { 1:10, 2:20, 3:30 }
# Is important here to cast because ".keys()" method returns a dict_keys object.
key_list = list( my_dic.keys() )

# Iterate on the list:
for k in key_list:
    print(key_list)
    print(my_dic)
    del( my_dic[k] )


print( my_dic )
# {}

4

आप पहले हटाने के लिए कुंजियों की एक सूची बना सकते हैं, और फिर उस सूची को हटाकर उन्हें हटा सकते हैं।

dict = {'one' : 1, 'two' : 2, 'three' : 3, 'four' : 4}
delete = []
for k,v in dict.items():
    if v%2 == 1:
        delete.append(k)
for i in delete:
    del dict[i]

इसके बजाय @ रिट्जेल के 1 समाधान (बड़े डिसटेंस w / o पूर्ण प्रतिलिपि पर कुशल) का एक डुप्लिकेट है। हालांकि एक "लंबे समय से पढ़ा" डब्ल्यू / ओ सूची समझ। फिर भी यह संभवतः तेज है?
kxr

3

एक ऐसा तरीका है जो उपयुक्त हो सकता है यदि आप जिस आइटम को हटाना चाहते हैं वह हमेशा तानाशाही की "शुरुआत" पर है

while mydict:
    key, value = next(iter(mydict.items()))
    if should_delete(key, value):
       del mydict[key]
    else:
       break

"शुरुआत" केवल कुछ पायथन संस्करणों / कार्यान्वयन के लिए संगत होने की गारंटी है। उदाहरण के लिए व्हाट्स न्यू इन पायथन 3.7

प्रमुख वस्तुओं के सम्मिलन-आदेश संरक्षण प्रकृति को पायथन भाषा की कल्पना का आधिकारिक हिस्सा घोषित किया गया है।

इस तरह से उस हुकुम की एक प्रति बच जाती है जो बहुत सारे अन्य उत्तर सुझाते हैं, कम से कम पायथन 3 में।


1

मैंने पायथन 3 में उपरोक्त समाधानों की कोशिश की, लेकिन यह मेरे लिए केवल एक ही काम कर रहा है जब वस्तुओं को एक तानाशाही में संग्रहीत किया जाता है। मूल रूप से आप अपने मूल शब्दकोश में प्रविष्टियों को हटाते समय अपने हुक्म की प्रति () और उस पर पुनरावृति करते हैं।

        tmpDict = realDict.copy()
        for key, value in tmpDict.items():
            if value:
                del(realDict[key])
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.