কোনও অভিধান থেকে আইটেমগুলি পুনরাবৃত্তি করার সময় কীভাবে মুছবেন?


295

পাইথনের অভিধান থেকে আইটেমগুলি পুনরুক্তি করার সময় এটি কী মুছে ফেলা বৈধ?

উদাহরণ স্বরূপ:

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

ধারণাটি হ'ল ডিকশনারি থেকে একটি নির্দিষ্ট শর্ত পূরণ না করে এমন উপাদানগুলি সরিয়ে ফেলা, পরিবর্তে একটি নতুন অভিধান তৈরি করা যা তার পুনরাবৃত্তি হওয়া একটির উপসেট।

এটি কি ভাল সমাধান? আরও কি মার্জিত / দক্ষ উপায় আছে?


1
খুব আকর্ষণীয় উত্তর সহ একটি সম্পর্কিত প্রশ্ন: stackoverflow.com/questions/9023078/…
সর্বাধিক

সহজেই চেষ্টা করা যেত। যদি এটি ব্যর্থ হয় তবে এটি বৈধ নয়।
ট্রায়ারিলিয়ন

26
@ ট্র্যারিওন ওয়ান সহজেই চেষ্টা করতে পারত ... এবং সহজেই মূল্যবোধের কিছুই জানত না। যদি সফল হয়, এটা না অগত্যা বৈধ। এজ কেস এবং অপ্রত্যাশিত সতর্কতা প্রচুর ab এই প্রশ্নটি পাইথোনিস্টাস সকলের কাছে অপ্রয়োজনীয় আগ্রহের বিষয়। "সহজেই চেষ্টা করা যেতে পারে!" এর আদেশে হ্যান্ড-ওয়েভিং বরখাস্ত! অসহায় এবং স্ট্যাকওভারফ্লো তদন্তের অনুসন্ধানী চেতনার বিপরীতে।
সিসিল কারি

পড়ার পর সর্বোচ্চ 's সংশ্লিষ্ট প্রশ্ন , আমি একমত নয়। আপনি সম্ভবত বিরক্তিকরভাবে গভীরতর প্রশ্ন এবং এর পরিবর্তে এর ভাল-লিখিত উত্তরগুলি অনুধাবন করতে চান। আপনার পাইথোনিক মন ফুঁকানো হবে।
সিসিল কারি

1
@ সিসিলকিউরি এখানে ধারণা উপস্থাপনের আগে নিজের জন্য একটি ধারণা পরীক্ষা করা যদি আমার ভুল না হয় তবে স্ট্যাকওভারফ্লোয়ের চেতনায় এটি এক রকম। এটাই আমি জানাতে চেয়েছিলাম। দুঃখিত যে কারণে যদি কোনও ঝামেলা হয়েছে। এছাড়াও আমি মনে করি এটি একটি ভাল প্রশ্ন এবং এটিকে নিম্নচোট করেনি। জোছন রিটসেলের উত্তর আমার সবচেয়ে ভাল লেগেছে । আমি মনে করি না যে দ্বিতীয় ধাপে মুছতে মুছতে মুছতে ফ্লাইতে মুছে ফেলার জন্য একজনকে সমস্ত জিনিস করা দরকার do এটি আমার দৃষ্টিতে পছন্দসই উপায় হওয়া উচিত।
ট্রায়ারিলিয়ন

উত্তর:


305

সম্পাদনা করুন:

এই উত্তর পাইথন 3 এর জন্য কাজ করবে না এবং একটি দেবে RuntimeError

রানটাইম-এরির: পুনরাবৃত্তির সময় অভিধানের আকার পরিবর্তন হয়েছে।

এটি ঘটে কারণ mydict.keys()একটি পুনরাবৃত্তির তালিকা দেয় না returns মন্তব্যে নির্দেশিত হিসাবে কেবল 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
@ টিমলিশার মন্তব্যে বিস্তারিত জানাতে ... এটি পাইথন 3 এ কাজ করবে না
সর্বোচ্চ

99
@ সর্বাধিকের বিস্তৃততার সাথে বিস্তারিত জানাতে, আপনি উপরের কোডটি 2to3 দিয়ে রূপান্তর করলে এটি কাজ করবে। ডিফল্ট fixers এক লুপ চেহারা চান করতে হবে for k, v in list(mydict.items()):যা পাইথন 3 সৎক্রিয়াতে একই keys()হয়ে list(keys())
ওয়াল্টার মুন্ড

8
এটি কাজ করে না। আমি একটি ত্রুটি পেয়েছি:RuntimeError: dictionary changed size during iteration
টম জ্যাটো - মনিকা

14
ওয়াল্টার হিসাবে টম্যাজাটো নির্দেশ করেছেন, পাইথন 3 এর জন্য আপনাকে for k in list(mydict.keys()): পাইথন 3 ব্যবহার করতে হবে কীগুলি () পদ্ধতিটি একটি পুনরুক্তি তৈরি করে এবং পুনরাবৃত্তির সময় ডিক আইটেমগুলি মুছতেও অস্বীকার করে। একটি তালিকা () কল যুক্ত করে কীগুলি () পুনরুক্তিকারীকে একটি তালিকায় পরিণত করুন। সুতরাং আপনি যখন লুপটির শরীরে থাকবেন তখন আপনি আর অভিধানে নিজেই পুনরাবৃত্তি করতে পারবেন না।
জেফ ক্রম্পটন

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]
এক্সো

প্রথম দ্রবণটি এখন পর্যন্ত এই থ্রেডের বড় ডিক্টের জন্য কেবল দক্ষ one কারণ এটি একটি পূর্ণ দৈর্ঘ্যের অনুলিপি তৈরি করে না।
কেএক্সআর

21

কোনও সংগ্রহ পুনরাবৃত্তি করার সময় আপনি এটি সংশোধন করতে পারবেন না। এইভাবে পাগলামিটি রয়েছে - উল্লেখযোগ্যভাবে, যদি আপনাকে বর্তমান আইটেমটি মুছতে এবং মুছতে দেওয়া হয়, তবে পুনরাবৃত্তিকে (+1) এগিয়ে যেতে হবে এবং পরবর্তী কলটি আপনাকে next(+২) এর বাইরে নিয়ে যেতে হবে, তাই আপনি চাইবেন একটি উপাদান বাদ দেওয়া শেষ করুন (আপনি মুছেছেন তার পিছনে একটি)। আপনার দুটি বিকল্প রয়েছে:

  • সমস্ত কী (বা মানগুলি বা উভয়ই আপনার প্রয়োজনের উপর নির্ভর করে) অনুলিপি করুন, তারপরে পুনরাবৃত্তি করুন। আপনি .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

পরিবর্তে একটি অনুলিপি দ্বারা ইটারেট করুন, যেমনটি ফিরে এসেছে items():

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

1
এটি তেমন কোনও তাত্পর্যপূর্ণ নয় - তবে আপনি del vসরাসরি পারবেন না , তাই আপনি প্রতিটি v এর একটি অনুলিপি তৈরি করেছেন যা আপনি কখনই ব্যবহার করতে যাচ্ছেন না এবং কীভাবে আপনাকে আইটেমগুলি অ্যাক্সেস করতে হবে। dict.keys()একটি ভাল পছন্দ।
jscs

2
@ জোশ: এটি vমোছার জন্য একটি মানদণ্ড হিসাবে আপনার কতটা প্রয়োজন হবে তার উপর নির্ভর করে ।
Ignacio Vazquez-Abram

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']

পাইথন 2 এবং পাইথন 3 এ দু'জনেই কাজ করে।


আপনার ডেটাসেট বড় হওয়ার ক্ষেত্রে এটি ভাল নয়। এটি মেমরিতে সমস্ত বস্তু অনুলিপি করছে, তাই না?
এএফপি_ 555

1
@ এএফপি_৫৫৫ হ্যাঁ - আমার লক্ষ্যটি পরিষ্কার, সমান্তরাল, পাইথোনিক কোডের জন্য। আপনার যদি মেমরির দক্ষতার প্রয়োজন হয় তবে আমার জানা সবচেয়ে ভাল পদ্ধতির পুনরাবৃত্তি করা এবং মুছে ফেলার জন্য কীগুলির একটি তালিকা বা সংরক্ষণ করার জন্য আইটেমগুলির একটি নতুন ডিক তৈরি করা। পাইথনের সাথে সৌন্দর্য আমার অগ্রাধিকার; বড় ডেটাসেটের জন্য আমি গো বা মরিচা ব্যবহার করছি।
আরএসবান

9

আপনি অভিধান বোঝার ব্যবহার করতে পারেন।

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


এটি সর্বাধিক পাইথোনিক।
ইয়াহোসেফ

তবে এটি dজায়গায় পরিবর্তনের পরিবর্তে একটি নতুন অভিধান তৈরি করে ।
এরিস্টেড

9

পাইথন 3 দিয়ে, ডিক.কেজগুলিতে পুনরাবৃত্তি () অভিধানের আকার ত্রুটি বাড়িয়ে তুলবে। আপনি এই বিকল্প পদ্ধতি ব্যবহার করতে পারেন:

পাইথন 3 দিয়ে পরীক্ষিত, এটি সূক্ষ্মভাবে কাজ করে এবং ত্রুটিটি " পুনরাবৃত্তির সময় অভিধানের পরিবর্তিত আকার " উত্থাপিত হয় না:

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 ম সমাধানের ডুপ্লিকেট (বড় ডিক্টে ডাব্লু / ও পুরো অনুলিপি কার্যকর)। যদিও একটি "দীর্ঘ পঠিত" ডাব্লু / ও তালিকা বোধগম্য। তবুও এটি তবুও কি দ্রুততর?
kxr

3

আপনি যে আইটেমগুলি মুছতে চান তা সর্বদা ডিক পুনরাবৃত্তির "শুরু" এ থাকলে এমন একটি উপায় রয়েছে যা উপযুক্ত হতে পারে

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

"শুরু" কেবলমাত্র পাইথন সংস্করণ / বাস্তবায়নের জন্য সামঞ্জস্যপূর্ণ to পাইথন ৩.7-এ নতুন কী থেকে উদাহরণস্বরূপ

ডিক বস্তুর সন্নিবেশ-অর্ডার সংরক্ষণের প্রকৃতিটি পাইথন ভাষা অনুচ্ছেদের একটি সরকারী অংশ হিসাবে ঘোষণা করা হয়েছে।

এই উপায়টি ডিকের অনুলিপি এড়িয়ে চলে যা অন্যান্য উত্তরগুলির অনেকগুলি পরামর্শ দেয়, কমপক্ষে পাইথন 3 এ।


1

পাইথন 3-তে আমি উপরের সমাধানগুলি চেষ্টা করেছি তবে ডিক্টে অবজেক্টগুলি সংরক্ষণ করার সময় এই একমাত্র আমার পক্ষে কাজ করছে বলে মনে হয়। মূলত আপনি আপনার ডিকের একটি অনুলিপি তৈরি করুন () এবং এটির পুনরুক্তি করার সময় আপনার মূল অভিধানে এন্ট্রিগুলি মুছে ফেলা হবে।

        tmpDict = realDict.copy()
        for key, value in tmpDict.items():
            if value:
                del(realDict[key])
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.