"रनटाइमटाइम" से कैसे बचें: पुनरावृति के दौरान शब्दकोश का आकार बदल गया है?


258

मैंने अन्य सभी प्रश्नों की जाँच एक ही त्रुटि के साथ की है लेकिन अभी तक कोई उपयोगी समाधान नहीं मिला है / /

मेरे पास सूचियों का एक शब्दकोश है:

d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

जिसमें कुछ मान खाली हैं। इन सूचियों को बनाने के अंत में, मैं अपना शब्दकोश वापस करने से पहले इन खाली सूचियों को हटाना चाहता हूं। वर्तमान में मैं इसे इस प्रकार करने का प्रयास कर रहा हूं:

for i in d:
    if not d[i]:
        d.pop(i)

हालाँकि, यह मुझे रनटाइम त्रुटि दे रहा है। मुझे पता है कि आप इसके माध्यम से पुनरावृति करते हुए किसी शब्दकोश में तत्वों को जोड़ / हटा नहीं सकते हैं ... तब इसके आसपास क्या होगा?

जवाबों:


454

पायथन में 2.x कॉलिंग keysउस कुंजी की एक प्रति बनाती है जिसे आप संशोधित करते हुए उस पर पुनरावृति कर सकते हैं dict:

for i in d.keys():

ध्यान दें कि यह पायथन 3.x में काम नहीं करता है क्योंकि keysएक सूची के बजाय एक पुनरावृत्त लौटाता है।

एक और तरीका यह listहै कि बनाई जाने वाली चाबियों की एक कॉपी को मजबूर करने के लिए उपयोग किया जाए। यह पायथन 3.x में भी काम करता है:

for i in list(d):

1
मेरा मानना ​​है कि 'कॉलिंग आपको उन कुंजियोंkeys की एक प्रति बनाती है, जिन्हें आप सही ढंग से उर्फ' कुंजी 'पर प्रसारित कर सकते हैं ? अन्यथा एक एकल कुंजी पर एक पुनरावृति कैसे हो सकती है? मैं इस तरह से plural
नाइटिंग

6
या सूची के बजाय टपल करें क्योंकि यह तेज है।
ब्रामबोर

8
अजगर 3.x के व्यवहार को स्पष्ट करने के लिए, d.keys () एक पुनरावृत्ति देता है (एक पुनरावृत्ति नहीं) जिसका अर्थ है कि यह सीधे शब्दकोश की कुंजी पर एक दृश्य है। का उपयोग करना for i in d.keys()वास्तव में अजगर 3.x में सामान्य रूप से काम करता है , लेकिन क्योंकि यह शब्दकोश की कुंजियों के एक पुनरावृत्ति दृश्य पर चलने वाला है, d.pop()लूप के दौरान कॉल करने से आपको मिली त्रुटि के समान होता है। for i in list(d)अपने जैसे विशेष परिस्थितियों के लिए पुनरावृत्ति करने से पहले एक सूची में चाबी की नकल करने के लिए थोड़ा अक्षम अजगर 2 व्यवहार का अनुकरण करता है।
माइकल क्रेब्स

जब आप किसी वस्तु को आंतरिक श्रुति में हटाना चाहते हैं तो आपका python3 समाधान काम नहीं करता है। उदाहरण के लिए, आपके पास डी और ए में तानाशाह बी हैं, यदि आप ताना बी में ऑब्जेक्ट को हटाना चाहते हैं तो यह त्रुटि होती है
अली-टी

1
Python3.x में, list(d.keys())उसी तरह का आउटपुट बनाता है list(d), जैसे रिटर्न listऑन dictद कीज़। keysकॉल (हालांकि नहीं है कि महंगा) अनावश्यक है।
सीन ब्रेकेनरिज

46

संबंधित आइटम्स को नए श्रुंखला में कॉपी करने के लिए सिर्फ डिक्शनरी कॉम्प्रिहेंशन का उपयोग करें

>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = { k : v for k,v in d.iteritems() if v}
>>> d
{'a': [1], 'b': [1, 2]}

इसके लिए अजगर 3 में

>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = { k : v for k,v in d.items() if v}
>>> d
{'a': [1], 'b': [1, 2]}

11
d.iteritems()मुझे एक त्रुटि दी। मैंने d.items()इसके बजाय इस्तेमाल किया - python3 का उपयोग करना
wcyn

4
यह ओपी के प्रश्न में समस्या के लिए काम करता है। हालाँकि जो भी लोग इस RuntimeError को मल्टी-थ्रेडेड कोड में हिट करने के बाद यहां आए हैं, वे इस बात से अवगत रहें कि CPython की GIL सूची बोध के बीच में भी जारी हो सकती है और आपको इसे अलग तरीके से ठीक करना होगा।
यिरखा

40

आपको केवल "कॉपी" का उपयोग करना होगा:

इस तरह से आप मूल डिक्शनरी फ़ील्ड्स पर पुनरावृति करते हैं और फ़्लाय पर वांछित तानाशाही (डी डिक्टेड) ​​को बदल सकते हैं। यह प्रत्येक अजगर संस्करण पर काम करता है, इसलिए यह अधिक स्पष्ट है।

In [1]: d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

In [2]: for i in d.copy():
   ...:     if not d[i]:
   ...:         d.pop(i)
   ...:         

In [3]: d
Out[3]: {'a': [1], 'b': [1, 2]}


13

मैं पहली जगह में खाली सूची डालने से बचने की कोशिश करूंगा, लेकिन, आमतौर पर उपयोग करूंगा:

d = {k: v for k,v in d.iteritems() if v} # re-bind to non-empty

अगर 2.7 से पहले:

d = dict( (k, v) for k,v in d.iteritems() if v )

या केवल:

empty_key_vals = list(k for k in k,v in d.iteritems() if v)
for k in empty_key_vals:
    del[k]

+1: अंतिम विकल्प दिलचस्प है क्योंकि यह केवल उन वस्तुओं की कुंजी को कॉपी करता है जिन्हें हटाने की आवश्यकता होती है। यह बेहतर प्रदर्शन दे सकता है यदि केवल थोड़े से सामान को हुक के आकार के सापेक्ष हटाने की आवश्यकता हो।
मार्क बायर्स

@ मार्कर्स यूप - और यदि बड़ी संख्या करते हैं, तो हुकुम को फिर से फ़िल्टर करने वाले नए के लिए फिर से बांधना एक बेहतर विकल्प है। यह हमेशा उम्मीद करता है कि संरचना कैसे काम करे
जॉन क्लेमेंट्स

4
रिबॉन्डिंग के साथ एक खतरा यह है कि अगर कार्यक्रम में कहीं एक वस्तु थी जो पुराने तानाशाह के संदर्भ में थी तो उसमें बदलाव नहीं दिखेंगे। यदि आप निश्चित हैं कि ऐसा नहीं है, तो सुनिश्चित करें ... यह एक उचित दृष्टिकोण है, लेकिन यह समझना महत्वपूर्ण है कि यह मूल तानाशाही को संशोधित करने के समान नहीं है।
मार्क बायर्स

@ मार्कर्स बेहद अच्छे बिंदु - आप और मैं जानते हैं कि (और अनगिनत अन्य), लेकिन यह सभी के लिए स्पष्ट नहीं है। और मैं मेज यह भी आप पीछे :) में नहीं काट लिया है पर पैसा डाल देता हूँ
जॉन क्लेमेंट्स

खाली प्रविष्टियों को सम्मिलित करने से बचने की बात बहुत अच्छी है।
मैग्नस बोडिन

12

पायथन 3 के लिए:

{k:v for k,v in d.items() if v}

अच्छा और संक्षिप्त। पायथन 2.7 में भी मेरे लिए काम किया।
डॉनरनडॉन

6

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

    for key in list(d):
        if not d[key]: 
            d.pop(key)

1

इस तरह की स्थितियों के लिए, मैं मूल प्रति को संशोधित करते हुए उस प्रति के माध्यम से एक गहरी प्रतिलिपि और लूप बनाना पसंद करता हूं।

यदि लुकअप फ़ील्ड एक सूची के भीतर है, तो आप सूची के लूप के लिए गणना कर सकते हैं और फिर मूल रूप से फ़ील्ड को एक्सेस करने के लिए इंडेक्स के रूप में स्थिति निर्दिष्ट कर सकते हैं।


1

यह मेरे लिए काम किया:

dict = {1: 'a', 2: '', 3: 'b', 4: '', 5: '', 6: 'c'}
for key, value in list(dict.items()):
    if (value == ''):
        del dict[key]
print(dict)
# dict = {1: 'a', 3: 'b', 6: 'c'}  

डिक्शनरी आइटम्स को लिस्ट में डालना उसके आइटम्स की एक लिस्ट बनाता है, जिससे आप इस पर इट्रेट कर सकते हैं और इससे बच सकते हैं RuntimeError


1

तानाशाह = {"stName": "asas"} कुंजियाँ = तानाशाही () सूची (कीज़) में कुंजी के लिए: तानाशाही [key.upper ()] = 'नया मूल्य' प्रिंट (str (तानाशाह))


0

रनटाइम त्रुटि का कारण यह है कि आप डेटा संरचना के माध्यम से पुनरावृत्ति नहीं कर सकते हैं, जबकि इसकी संरचना पुनरावृत्ति के दौरान बदल रही है।

आप जिस चीज़ की तलाश कर रहे हैं उसे प्राप्त करने का एक तरीका यह है कि सूची का उपयोग करें कि आप जिन कुंजियों को हटाना चाहते हैं, उन्हें सूचीबद्ध करें और फिर सूची के माध्यम से पुनरावृत्ति करते समय पहचाने गए कुंजी को हटाने के लिए शब्दकोश पर पॉप फ़ंक्शन का उपयोग करें।

d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}
pop_list = []

for i in d:
        if not d[i]:
                pop_list.append(i)

for x in pop_list:
        d.pop(x)
print (d)

0

पायथन 3 पुनरावृति (ऊपर दिए गए लूप के लिए उपयोग) करते समय विलोपन की अनुमति नहीं देता है। करने के लिए विभिन्न विकल्प हैं; एक सरल तरीका निम्नलिखित लाइन को बदलना है

for i in x.keys():

साथ में

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