সমস্ত নেস্টেড অভিধানের মানগুলি লুপ করবেন?


120
for k, v in d.iteritems():
    if type(v) is dict:
        for t, c in v.iteritems():
            print "{0} : {1}".format(t, c)

আমি একটি অভিধানের মধ্য দিয়ে লুপ করার চেষ্টা করছি এবং সমস্ত মূল মান জোড় মুদ্রণ করব যেখানে মান কোনও নেস্টেড অভিধান নয় dictionary মানটি যদি একটি অভিধান হয় তবে আমি এটিতে গিয়ে এর মূল মান জোড়গুলি মুদ্রণ করতে চাই ... ইত্যাদি। কোন সাহায্য?

সম্পাদনা

এ কেমন? এটি এখনও কেবল একটি জিনিস প্রিন্ট করে।

def printDict(d):
    for k, v in d.iteritems():
        if type(v) is dict:
            printDict(v)
        else:
            print "{0} : {1}".format(k, v)

সম্পূর্ণ পরীক্ষার কেস

অভিধান:

{u'xml': {u'config': {u'portstatus': {u'status': u'good'}, u'target': u'1'},
      u'port': u'11'}}

ফলাফল:

xml : {u'config': {u'portstatus': {u'status': u'good'}, u'target': u'1'}, u'port': u'11'}

1
আপনার মত মনে হচ্ছে পুনরাবৃত্তি, তবে বিবরণটি নিশ্চিত হওয়ার পক্ষে যথেষ্ট পরিষ্কার নয়। ইনপুট / আউটপুট সম্পর্কে কিছু উদাহরণ সম্পর্কে কি? এছাড়াও, আপনার কোডে কি সমস্যা আছে?
নিক্লাস বি।

2
পাইথনে একটি স্থির পুনরাবৃত্তি সীমা রয়েছে: ডকস.পিথন.আর.লিবেরি
ডাঃ জানু-ফিলিপ গেহর্ক্ক

2
@ জান-ফিলিপ জিহরস্কে: পুনরাবৃত্তি না করে গাছের মতো ডেটা স্ট্রাকচারে অ্যালগরিদমগুলি প্রয়োগ করা সহজ আত্মহত্যা।
নিক্লাস বি।

2
@ টাক্কুন: আপনি dictএকটি পরিবর্তনশীল নাম হিসাবে ব্যবহার করছেন । কখনও এটি করবেন না (এ কারণেই এটি ব্যর্থ হয়)।
নিক্লাস বি।

3
@ নিক্লাসবি।, পুনরায়: "আত্মহত্যা": আমি স্যাচারনের অ্যালগরিদমের একটি পুনরাবৃত্ত সংস্করণ প্রয়োগ করেছি এবং এর মাত্র দুটি লাইন দীর্ঘ এবং এখনও অনুসরণ করা বেশ সহজ। এছাড়াও গাছ থেকে সাধারণ গ্রাফগুলিতে যাওয়ার সময় পুনরাবৃত্তির পুনরাবৃত্তির অনুবাদ করা প্রায়ই প্রয়োজন।
ফ্রেড ফু

উত্তর:


157

যেমন নিক্লাস বলেছেন, আপনার পুনরাবৃত্তি দরকার, অর্থাত আপনার ডিকটি প্রিন্ট করতে কোনও ফাংশন সংজ্ঞায়িত করতে চান এবং মানটি যদি ডিক হয় তবে আপনি এই নতুন ডিকটি ব্যবহার করে আপনার মুদ্রণ ফাংশনটি কল করতে চান।

কিছুটা এইরকম :

def myprint(d):
    for k, v in d.items():
        if isinstance(v, dict):
            myprint(v)
        else:
            print("{0} : {1}".format(k, v))

3
ছোট উন্নতি। মাইপ্রিন্ট (v) কল করার আগে মুদ্রণ (কে) যুক্ত করুন।
নাওমি ফ্রিডম্যান

পুনরাবৃত্তি সঙ্গে এটি তুচ্ছ।
সার্জাজাচ

36

আপনার নিজের পুনরাবৃত্তির প্রয়োগ বা স্ট্যাকের সাথে পুনরাবৃত্ত সমতুল্য লিখলে সম্ভাব্য সমস্যা রয়েছে potential এই উদাহরণটি দেখুন:

    dic = {}
    dic["key1"] = {}
    dic["key1"]["key1.1"] = "value1"
    dic["key2"]  = {}
    dic["key2"]["key2.1"] = "value2"
    dic["key2"]["key2.2"] = dic["key1"]
    dic["key2"]["key2.3"] = dic

সাধারণ অর্থে, নেস্টেড ডিকশনারি হ'ল ডেটা স্ট্রাকচারের মতো একটি এন-নেরি ট্রি। তবে সংজ্ঞাটি ক্রস এজ বা এমনকি পিছনের প্রান্তের সম্ভাবনা বাদ দেয় না (এইভাবে আর গাছ নেই)। উদাহরণস্বরূপ, এখানে key2.2 থেকে অভিধান ঝুলিতে key1 , key2.3 সমগ্র অভিধান পয়েন্ট (ব্যাক প্রান্ত / চক্র)। যখন পিছনের প্রান্তটি (চক্র) থাকবে তখন স্ট্যাক / পুনরাবৃত্তি অসীমভাবে চলবে।

                          root<-------back edge
                        /      \           |
                     _key1   __key2__      |
                    /       /   \    \     |
               |->key1.1 key2.1 key2.2 key2.3
               |   /       |      |
               | value1  value2   |
               |                  | 
              cross edge----------|

আপনি যদি এই প্রয়োগটি দিয়ে সিকারন থেকে মুদ্রণ করেন

    def myprint(d):
      for k, v in d.items():
        if isinstance(v, dict):
          myprint(v)
        else:
          print "{0} : {1}".format(k, v)

আপনি এই ত্রুটি দেখতে পাবেন:

    RuntimeError: maximum recursion depth exceeded while calling a Python object

প্রেরকের কাছ থেকে বাস্তবায়নের ক্ষেত্রেও একই রকম

একইভাবে, ফ্রেড ফু থেকে আপনি এই প্রয়োগের সাথে একটি অসীম লুপ পান :

    def myprint(d):
        stack = list(d.items())
        while stack:
            k, v = stack.pop()
            if isinstance(v, dict):
                stack.extend(v.items())
            else:
                print("%s: %s" % (k, v))

তবে পাইথন আসলে নেস্টেড অভিধানে চক্র সনাক্ত করে:

    print dic
    {'key2': {'key2.1': 'value2', 'key2.3': {...}, 
       'key2.2': {'key1.1': 'value1'}}, 'key1': {'key1.1': 'value1'}}

"{...}" হল যেখানে একটি চক্র সনাক্ত হয়েছে is

মুন্দ্রার অনুরোধ অনুসারে এটি চক্র এড়ানোর একটি উপায় (ডিএফএস):

def myprint(d): 
  stack = list(d.items()) 
  visited = set() 
  while stack: 
    k, v = stack.pop() 
    if isinstance(v, dict): 
      if k not in visited: 
        stack.extend(v.items()) 
      else: 
        print("%s: %s" % (k, v)) 
      visited.add(k)

তাহলে আপনি কীভাবে পুনরাবৃত্ত সমাধান সমাধান করবেন?
dreftymac

2
@dreftymac আমি চক্রে যাওয়া এড়াতে কীগুলির জন্য একটি পরিদর্শন করা সেট যুক্ত করব:def myprint(d): stack = d.items() visited = set() while stack: k, v = stack.pop() if isinstance(v, dict): if k not in visited: stack.extend(v.iteritems()) else: print("%s: %s" % (k, v)) visited.add(k)
টেংগার

1
এই বিষয়টি চিহ্নিত করার জন্য ধন্যবাদ. উত্তরে আপনার কোড সহ কিছু মনে করবেন? আমি মনে করি এটি আপনার দুর্দান্ত উত্তরটি সম্পূর্ণ করে।
মুনড্রা

Python3 জন্য ব্যবহার list(d.items())যেমন d.items()আয় একটি দৃশ্য, না একটি তালিকা, এবং ব্যবহার v.items()পরিবর্তেv.iteritems()
ম্যাক্স

33

যেহেতু একটি dictপুনরাবৃত্তিযোগ্য, আপনি কেবল কয়েকটি ছোট ছোট পরিবর্তন করে এই সমস্যার জন্য ক্লাসিক নেস্টেড কনটেইনার পুনরাবৃত্ত সূত্রটি প্রয়োগ করতে পারেন । এখানে পাইথন 2 সংস্করণ রয়েছে (3 এর জন্য নীচে দেখুন):

import collections
def nested_dict_iter(nested):
    for key, value in nested.iteritems():
        if isinstance(value, collections.Mapping):
            for inner_key, inner_value in nested_dict_iter(value):
                yield inner_key, inner_value
        else:
            yield key, value

টেস্ট:

list(nested_dict_iter({'a':{'b':{'c':1, 'd':2}, 
                            'e':{'f':3, 'g':4}}, 
                       'h':{'i':5, 'j':6}}))
# output: [('g', 4), ('f', 3), ('c', 1), ('d', 2), ('i', 5), ('j', 6)]

পাইথন 2-তে, এমন একটি কাস্টম তৈরি করা সম্ভব হতে পারে Mappingযা যোগ্য হিসাবে যোগ্য হয় Mappingতবে এটি ধারণ করে না iteritems, এক্ষেত্রে এটি ব্যর্থ হবে। দস্তাবেজগুলি নির্দেশ করে না যে এটির iteritemsজন্য প্রয়োজনীয় Mapping; অন্যদিকে, উত্স প্রকারকে Mappingএকটি iteritemsপদ্ধতি দেয় । সুতরাং কাস্টম জন্য Mappings, collections.Mappingস্পষ্টভাবে ক্ষেত্রে ক্ষেত্রে উত্তরাধিকার ।

পাইথন 3-তে, বেশ কয়েকটি উন্নতি করতে হবে। পাইথন ৩.৩ অনুসারে, বিমূর্ত বেস ক্লাসগুলি থাকে collections.abccollectionsপিছনের সামঞ্জস্যের জন্য তারা খুব বেশি থাকে , তবে আমাদের অ্যাবস্ট্রাক্ট বেস ক্লাসগুলি এক নামের জায়গাতে একত্রে করা আরও ভাল। সুতরাং এই abcথেকে আমদানি collections। পাইথন ৩.৩ এছাড়াও যোগ করে yield from, যা কেবলমাত্র এই ধরণের পরিস্থিতিতে তৈরি করা হয়েছে। এটি খালি সিনট্যাকটিক চিনি নয়; এটি কর্টিনগুলির সাথে দ্রুত কোড এবং আরও বুদ্ধিমান মিথস্ক্রিয়ায় নিয়ে যেতে পারে ।

from collections import abc
def nested_dict_iter(nested):
    for key, value in nested.items():
        if isinstance(value, abc.Mapping):
            yield from nested_dict_iter(value)
        else:
            yield key, value

3
isinstance(item, collections.Iterable)এর কোনও গ্যারান্টি নেই hasattr(item, "iteritems")। জন্য চেক collections.Mappingকরা ভাল।
ফ্রেড ফু

1
@ এলারম্যানস, আপনি অবশ্যই ঠিক বলেছেন। আমি ভাবছিলাম যে Iterableব্যবহারটি এই সমাধানটিকে আরও সাধারণীকরণ করে তুলবে, ভুলে যাবেন, সম্ভবত, পুনরাবৃত্তিগুলি অগত্যা হয় না iteritems
প্রেরক

এই উত্তরের জন্য +1 কারণ এটি একটি সাধারণ সমাধান যা এই সমস্যার জন্য কাজ করে, তবে এটি কেবল মানগুলি মুদ্রণের মধ্যে সীমাবদ্ধ নয়। @ টাক্কুন আপনার অবশ্যই এই বিকল্পটি বিবেচনা করা উচিত। দীর্ঘমেয়াদে আপনি মানগুলি মুদ্রণের চেয়ে আরও বেশি কিছু চাইবেন।
আলেজান্দ্রো পাইড

1
@ Seanny123, এই দিকে আমার দৃষ্টি আকর্ষণ করার জন্য ধন্যবাদ। পাইথন 3 ছবিটিকে কয়েকভাবে পরিবর্তন করে, বাস্তবে - আমি এটিকে নতুন yield fromরূপরেখা ব্যবহার করে এমন সংস্করণ হিসাবে পুনরায় লিখতে চলেছি ।
প্রেরক

25

বিকল্প পুনরাবৃত্তি সমাধান:

def myprint(d):
    stack = d.items()
    while stack:
        k, v = stack.pop()
        if isinstance(v, dict):
            stack.extend(v.iteritems())
        else:
            print("%s: %s" % (k, v))

2
হ্যাঁ, আমি এটি দেখতে দেখতে কল্পনা করেছি। ধন্যবাদ। সুতরাং এর সুবিধাটি হ'ল এটি অত্যন্ত গভীর বাসা বাঁধার জন্য স্ট্যাকটিকে উপচে ফেলবে না? নাকি এর অন্য কিছু আছে?
নিক্লাস বি।

@ নিক্লাসবি .: হ্যাঁ, এটিই প্রথম উপকার। এছাড়াও, এই সংস্করণটিকে স্ট্যাক (এ list) এর দ্বারা dequeএবং এমনকি কোনও অগ্রাধিকারের সারি দ্বারা প্রতিস্থাপনের মাধ্যমে খুব সহজেই বিভিন্ন ট্র্যাভারসাল অর্ডারে মানিয়ে নেওয়া যেতে পারে ।
ফ্রেড ফু

হ্যাঁ, বোঝা যায়। আপনাকে ধন্যবাদ এবং শুভ কোডিং :)
নিক্লাস বি।

হ্যাঁ, তবে এই সমাধানটি আমার এবং পুনরাবৃত্তির চেয়ে বেশি স্থান গ্রহণকারী।
স্ক্লামার

1
@ এমএসপিপি: মজা করার জন্য, আমি একটি মানদণ্ড তৈরি করেছি । আমার কম্পিউটারে, পুনরাবৃত্ত সংস্করণটি দ্রুততম এবং লারসম্যানগুলি তিনটি পরীক্ষার অভিধানের জন্য দ্বিতীয়। জেনারেটর ব্যবহার করে সংস্করণটি তুলনামূলকভাবে ধীর, যেমনটি প্রত্যাশা করা হয় (কারণ এটি বিভিন্ন জেনারেটর প্রসঙ্গে অনেক জাগ্রত করতে হয়)
নিক্লাস বি।

9

আমি কিছুটা আলাদা সংস্করণ লিখেছিলাম যা সেখানে যাওয়ার পথে কীগুলি ট্র্যাক করে

def print_dict(v, prefix=''):
    if isinstance(v, dict):
        for k, v2 in v.items():
            p2 = "{}['{}']".format(prefix, k)
            print_dict(v2, p2)
    elif isinstance(v, list):
        for i, v2 in enumerate(v):
            p2 = "{}[{}]".format(prefix, i)
            print_dict(v2, p2)
    else:
        print('{} = {}'.format(prefix, repr(v)))

আপনার ডেটাতে এটি মুদ্রণ করবে

data['xml']['config']['portstatus']['status'] = u'good'
data['xml']['config']['target'] = u'1'
data['xml']['port'] = u'11'

আপনার যদি সেভাবে এটির প্রয়োজন হয় তবে স্ট্রিংয়ের চেয়ে কীগুলির টিপল হিসাবে উপসর্গটি ট্র্যাক করার জন্য এটিকে সংশোধন করা সহজ।


কিভাবে একটি তালিকা আউটপুট যুক্ত করবেন?
শশ

5

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

def recursive_items(dictionary):
    for key, value in dictionary.items():
        if type(value) is dict:
            yield (key, value)
            yield from recursive_items(value)
        else:
            yield (key, value)

a = {'a': {1: {1: 2, 3: 4}, 2: {5: 6}}}

for key, value in recursive_items(a):
    print(key, value)

ছাপে

a {1: {1: 2, 3: 4}, 2: {5: 6}}
1 {1: 2, 3: 4}
1 2
3 4
2 {5: 6}
5 6

2

বিকল্প হিসাবে Iterative সমাধান:

def traverse_nested_dict(d):
    iters = [d.iteritems()]

    while iters:
        it = iters.pop()
        try:
            k, v = it.next()
        except StopIteration:
            continue

        iters.append(it)

        if isinstance(v, dict):
            iters.append(v.iteritems())
        else:
            yield k, v


d = {"a": 1, "b": 2, "c": {"d": 3, "e": {"f": 4}}}
for k, v in traverse_nested_dict(d):
    print k, v

ওটা কেমন? বিগ হে একই হওয়া উচিত (এটি O(depth)পুনরাবৃত্ত সমাধানের জন্য। একই সংস্করণে এটি প্রযোজ্য, যদি আমি সঠিকভাবে চিন্তা করি)।
নিক্লাস বি।

"স্ট্যাক কপি"? আপনি কি বিষয়ে কথা হয়? প্রতিটি ফাংশন কল একটি নতুন স্ট্যাকফ্রেম তৈরি করে। আপনার সমাধানটি itersসুস্পষ্ট স্ট্যাক হিসাবে ব্যবহার করে , তাই বিগ-ও মেমরির খরচ একই, বা আমি কি কিছু মিস করছি?
নিক্লাস বি।

@NiklasB। পুনরাবৃত্তি সর্বদা ওভারহেডের সাথে আসে, বিশদগুলির জন্য উইকিপিডিয়ায় এই বিভাগটি দেখুন: পুনরাবৃত্তাকারী দ্রবণটির স্ট্যাক ফ্রেমটি অনেক বড়।
স্ক্লামার

আপনার অবশ্যই সেই অনুচ্ছেদে ভুল বোঝাবুঝি হতে হবে। এটি আপনার বক্তব্য সমর্থন করতে কিছুই বলে না।
নিক্লাস বি।

1
@NiklasB। না, কারণ এখানে স্ট্যাক ফ্রেমটি কেবলমাত্র এটির এবং পুনরাবৃত্তির সমাধানের জন্য স্ট্যাক ফ্রেমে
ইটার

2

Scharron এর সমাধানের উপর ভিত্তি করে তালিকার সাথে কাজ করার একটি বিকল্প সমাধান

def myprint(d):
    my_list = d.iteritems() if isinstance(d, dict) else enumerate(d)

    for k, v in my_list:
        if isinstance(v, dict) or isinstance(v, list):
            myprint(v)
        else:
            print u"{0} : {1}".format(k, v)

2

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

    d = {
            "user": 10,
            "time": "2017-03-15T14:02:49.301000",
            "metadata": [
                {"foo": "bar"},
                "some_string"
            ]
        }


    def print_nested(d):
        if isinstance(d, dict):
            for k, v in d.items():
                print_nested(v)
        elif hasattr(d, '__iter__') and not isinstance(d, str):
            for item in d:
                print_nested(item)
        elif isinstance(d, str):
            print(d)

        else:
            print(d)

    print_nested(d)

আউটপুট:

    10
    2017-03-15T14:02:49.301000
    bar
    some_string

আমার এখানে অনেকটা একই সমস্যা রয়েছে স্ট্যাকওভারফ্লো . com/ জিজ্ঞাসা / 50642922/… । অভিধানের তালিকার শেষ উপাদানটি খুঁজে বের করার কোনও উপায় আছে, সেটি মুছুন এবং তারপরে একটি স্তর উপরে স্থানান্তর করুন? যদি মোছা না হয়, আমি একটি তালিকা তৈরি করতে চাই যেখানে সর্বশেষ উপাদানটি ডেটার গভীরতা তাই আমি তালিকাটি উল্টো করে মুছে
ফেলি

1

পাইথন ২-এর ফ্রেড ফু-র উত্তরের একটি পরিবর্তিত সংস্করণ এখানে রয়েছে মূল প্রতিক্রিয়াতে, কেবল নীড়ের গভীরতম স্তর আউটপুট। আপনি যদি তালিকা হিসাবে কীগুলি আউটপুট দেন তবে আপনি কীগুলি সমস্ত স্তরের জন্য রাখতে পারেন, যদিও তাদের রেফারেন্সের জন্য আপনাকে তালিকার একটি তালিকা উল্লেখ করতে হবে।

ফাংশনটি এখানে:

def NestIter(nested):
    for key, value in nested.iteritems():
        if isinstance(value, collections.Mapping):
            for inner_key, inner_value in NestIter(value):
                yield [key, inner_key], inner_value
        else:
            yield [key],value

কীগুলি উল্লেখ করতে:

for keys, vals in mynested: 
    print(mynested[keys[0]][keys[1][0]][keys[1][1][0]])

একটি তিন স্তরের অভিধানের জন্য।

একাধিক কী অ্যাক্সেস করার আগে আপনার স্তরের সংখ্যা জানতে হবে এবং স্তরের সংখ্যা স্থির থাকতে হবে (মানগুলির মধ্য দিয়ে পুনরাবৃত্তি করার সময় নীড়ের স্তরগুলি পরীক্ষা করার জন্য একটি ছোট্ট স্ক্রিপ্ট যোগ করা সম্ভব হতে পারে, তবে আমার নেই) তবুও এটি তাকান)।


1

আমি এই পদ্ধতিকে কিছুটা নমনীয় মনে করি, এখানে আপনি কেবল জেনারেটর ফাংশন সরবরাহ করছেন যা কী, মান জোড়গুলি নির্গত করে এবং সহজেই তালিকাগুলিতে পুনরাবৃত্তিও বাড়ানো যায়।

def traverse(value, key=None):
    if isinstance(value, dict):
        for k, v in value.items():
            yield from traverse(v, k)
    else:
        yield key, value

তারপরে আপনি নিজের myprintফাংশনটি লিখতে পারেন , তারপরে সেই মূল মানগুলি মুদ্রণ করতে পারেন ।

def myprint(d):
    for k, v in traverse(d):
        print(f"{k} : {v}")

একটি পরীক্ষা:

myprint({
    'xml': {
        'config': {
            'portstatus': {
                'status': 'good',
            },
            'target': '1',
        },
        'port': '11',
    },
})

আউটপুট:

status : good
target : 1
port : 11

আমি পাইথন 3.6 এ এটি পরীক্ষা করেছি।


0

এই উত্তরগুলি উপ-অভিধানের মাত্র 2 স্তরের জন্য কাজ করে। আরও চেষ্টা করুন:

nested_dict = {'dictA': {'key_1': 'value_1', 'key_1A': 'value_1A','key_1Asub1': {'Asub1': 'Asub1_val', 'sub_subA1': {'sub_subA1_key':'sub_subA1_val'}}},
                'dictB': {'key_2': 'value_2'},
                1: {'key_3': 'value_3', 'key_3A': 'value_3A'}}

def print_dict(dictionary):
    dictionary_array = [dictionary]
    for sub_dictionary in dictionary_array:
        if type(sub_dictionary) is dict:
            for key, value in sub_dictionary.items():
                print("key=", key)
                print("value", value)
                if type(value) is dict:
                    dictionary_array.append(value)



print_dict(nested_dict)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.