অভিধানের অভিধানগুলি কীভাবে মার্জ করবেন?


129

আমার একাধিক অভিধান একত্রিত করতে হবে, উদাহরণস্বরূপ আমার কাছে যা আছে তা এখানে:

dict1 = {1:{"a":{A}}, 2:{"b":{B}}}

dict2 = {2:{"c":{C}}, 3:{"d":{D}}

গাছের পাতাগুলির সাথে A B Cএবং Dথাকার মতো{"info1":"value", "info2":"value2"}

অভিধানের একটি অজানা স্তর (গভীরতা) রয়েছে, এটি হতে পারে {2:{"c":{"z":{"y":{C}}}}}

আমার ক্ষেত্রে এটি একটি ডিরেক্টরি / ফাইলের কাঠামোর প্রতিনিধিত্ব করে যেখানে নোড হ'ল ডক্স এবং ফাইলগুলি ফাইল হয়।

আমি তাদের পেতে মার্জ করতে চাই:

 dict3 = {1:{"a":{A}}, 2:{"b":{B},"c":{C}}, 3:{"d":{D}}}

পাইথনের সাহায্যে কীভাবে আমি তা সহজেই করতে পারি তা আমি নিশ্চিত নই।


আপনার অভিধানের স্বেচ্ছাসেবী গভীরতার জন্য আপনি কী চান? আপনি কি স্তর yপর্যন্ত চ্যাপ্টা চান cবা কি? আপনার উদাহরণটি অসম্পূর্ণ।
agf

এখানে আমার NestedDict বর্গ চেক করুন: stackoverflow.com/a/16296144/2334951 এটা মার্জ এবং আরো অনেক মত নেস্টেড অভিধান স্ট্রাকচার পরিচালনার নেই।
সিজিবার্থএডাম

3
সমাধানগুলির সন্ধানের জন্য প্রত্যেককে একটি সতর্কতা: এই প্রশ্নটি কেবল নেস্টেড ডিক্টস সম্পর্কে। বেশিরভাগ উত্তর কাঠামোর মধ্যে ডিক্টের তালিকার আরও জটিল ক্ষেত্রে সঠিকভাবে পরিচালনা করে না। : যদি আপনি এই ব্যবহার করে দেখুন নিচের @Osiloke উত্তর প্রয়োজন stackoverflow.com/a/25270947/1431660
SHernandez


উত্তর:


143

এটি আসলে বেশ জটিল - বিশেষত যদি আপনি কোনও কার্যকর ত্রুটি বার্তা চান যখন জিনিসগুলি অসঙ্গতিপূর্ণ হয়, সঠিকভাবে সদৃশ কিন্তু ধারাবাহিক এন্ট্রি গ্রহণ করার সময় (এখানে অন্য কোনও উত্তর দেয় না ...)

ধরে নিলাম আপনার বিপুল সংখ্যক এন্ট্রি নেই এমন একটি পুনরাবৃত্তি ফাংশন সবচেয়ে সহজ:

def merge(a, b, path=None):
    "merges b into a"
    if path is None: path = []
    for key in b:
        if key in a:
            if isinstance(a[key], dict) and isinstance(b[key], dict):
                merge(a[key], b[key], path + [str(key)])
            elif a[key] == b[key]:
                pass # same leaf value
            else:
                raise Exception('Conflict at %s' % '.'.join(path + [str(key)]))
        else:
            a[key] = b[key]
    return a

# works
print(merge({1:{"a":"A"},2:{"b":"B"}}, {2:{"c":"C"},3:{"d":"D"}}))
# has conflict
merge({1:{"a":"A"},2:{"b":"B"}}, {1:{"a":"A"},2:{"b":"C"}})

নোট করুন যে এই রূপান্তরিত হয় a- এর সামগ্রীতে bযোগ করা হয় a(এটিও ফিরে আসে)। আপনি যদি রাখতে চান তবে aএটি এটিকে কল করতে পারেন merge(dict(a), b)

এগ্রেফ (নীচে) উল্লেখ করেছেন যে আপনার কাছে দুটির বেশি ডিক্ট থাকতে পারে, এক্ষেত্রে আপনি ব্যবহার করতে পারেন:

reduce(merge, [dict1, dict2, dict3...])

যেখানে সবকিছু ডিক্টে যুক্ত হবে।

[দ্রষ্টব্য - আমি প্রথম যুক্তিটি পরিবর্তনের জন্য আমার প্রাথমিক উত্তরটি সম্পাদনা করেছি; যা ব্যাখ্যা করতে "হ্রাস" সহজ করে]

পাইথন 3 এ PS, আপনারও প্রয়োজন হবে from functools import reduce


1
তারপরে আপনি এটিকে দুটি reduceবা একটি স্বেচ্ছাসেবী সংখ্যার সাথে কাজ করতে সমতুল্য লুপের ভিতরে আটকে রাখতে পারেন dict। তবে আমি নিশ্চিত নই যে তিনি যা চান 2: {'c': {'z': {'y': {'info1': 'value', 'info2': 'value2'}}}, 'b': {'info1': 'value', 'info2': 'value2'}}তা এটিই করেন (তিনি পরিষ্কার ছিলেন না), আপনি তার দ্বিতীয় উদাহরণটি দিয়ে শেষ করেছেন , আমি নিশ্চিত নই যে সে চায় zএবং yচাটুকা হবে কিনা ?
agf

1
সেগুলি ডিরেক্টরি কাঠামো যাতে আমার মনে হয় না / সে কিছু চাটুকার চায়? ওহ, দুঃখিত, "একাধিক অভিধান" মিস হয়েছে। হ্যাঁ, হ্রাস করা ভাল হবে। যে যোগ করা হবে।
অ্যান্ড্রু কুক

এটি আমি যা চেয়েছিলাম ঠিক তাই করে! আমি দুঃখিত আমি যথেষ্ট পরিষ্কার ছিলাম না ... আমি ভেবেছিলাম আমি পাইথনের সাথে ঠিক আছি, মনে হয় না: - / নেস্টেড ডিক্টসের কারণে আমার একটি পুনরাবৃত্ত ফাংশন প্রয়োজন, এটি কাজ করে এবং আমি এটি বুঝতে পারি :) আমি না যদিও এটি হ্রাস
করেই

2
Dicts অধীনে চূড়ান্ত নেস্টেড স্তর হিসাবে তালিকা সঙ্গে কেউ জন্য, আপনি যদি এর পরিবর্তে দুটি তালিকা কনক্যাটেনেট ত্রুটির তোলা এটা করতে পারেন: a[key] = a[key] + b[key]। সহায়ক উত্তরের জন্য ধন্যবাদ।
কেভিনমিক মাই

1
> আপনি যদি কোনওটি রাখতে চান তবে আপনি এটিকে মার্জ (ডিক (ক), ক) নামে অভিহিত করতে পারেন Note দ্রষ্টব্য যে নেস্টেড ডিক্টস এখনও পরিবর্তিত হবে। এটি এড়াতে, ব্যবহার করুন copy.deepcopy
rcorre

30

জেনারেটর ব্যবহার করে এটি করার সহজ উপায় এখানে রয়েছে:

def mergedicts(dict1, dict2):
    for k in set(dict1.keys()).union(dict2.keys()):
        if k in dict1 and k in dict2:
            if isinstance(dict1[k], dict) and isinstance(dict2[k], dict):
                yield (k, dict(mergedicts(dict1[k], dict2[k])))
            else:
                # If one of the values is not a dict, you can't continue merging it.
                # Value from second dict overrides one in first and we move on.
                yield (k, dict2[k])
                # Alternatively, replace this with exception raiser to alert you of value conflicts
        elif k in dict1:
            yield (k, dict1[k])
        else:
            yield (k, dict2[k])

dict1 = {1:{"a":"A"},2:{"b":"B"}}
dict2 = {2:{"c":"C"},3:{"d":"D"}}

print dict(mergedicts(dict1,dict2))

এই মুদ্রণ:

{1: {'a': 'A'}, 2: {'c': 'C', 'b': 'B'}, 3: {'d': 'D'}}

আপনি যদি জেনারেটর থিম রাখতে চান তবে আপনি চেইন করতে পারেন (ডিক্ট.কিজ (), ডিক্ট.কিজ ())
অ্যান্ড্রু কুক ২

এটি কি নকল চাবি পাবেন না?
জেটেরেস

এটি একটি কাজটি কমপক্ষে আমার ডেটা সেট করে দেখে মনে হচ্ছে, তবে ফলন এবং জেনারেটরগুলি আমি কখনই ভালভাবে বুঝতে পারি নি কারণ আমি কেন অনেকটা হারিয়েছি, তবে আমি কিছুটা চেষ্টা করব, কার্যকর হতে পারে!
এফডিএক্স

আহ, হ্যাঁ, এটি নকল কী পেতে হবে। দুঃখিত, আপনাকে এখনও সেটটিতে মোড়ানো দরকার, দুঃখিত।
অ্যান্ড্রু কুক

2
আমি এই বিশেষ সহায়ক। তবে নিকষ্টিংটি হ'ল ফাংশনটিকে প্যারামিটার হিসাবে বিরোধগুলি সমাধান করতে দেওয়া।
mentatkgs

25

এই প্রশ্নটির সাথে একটি সমস্যা হ'ল ডকের মানগুলি নির্বিচারে ডেটাগুলির জটিল টুকরো হতে পারে। এই এবং অন্যান্য উত্তরের উপর ভিত্তি করে আমি এই কোডটি নিয়ে এসেছি:

class YamlReaderError(Exception):
    pass

def data_merge(a, b):
    """merges b into a and return merged result

    NOTE: tuples and arbitrary objects are not handled as it is totally ambiguous what should happen"""
    key = None
    # ## debug output
    # sys.stderr.write("DEBUG: %s to %s\n" %(b,a))
    try:
        if a is None or isinstance(a, str) or isinstance(a, unicode) or isinstance(a, int) or isinstance(a, long) or isinstance(a, float):
            # border case for first run or if a is a primitive
            a = b
        elif isinstance(a, list):
            # lists can be only appended
            if isinstance(b, list):
                # merge lists
                a.extend(b)
            else:
                # append to list
                a.append(b)
        elif isinstance(a, dict):
            # dicts must be merged
            if isinstance(b, dict):
                for key in b:
                    if key in a:
                        a[key] = data_merge(a[key], b[key])
                    else:
                        a[key] = b[key]
            else:
                raise YamlReaderError('Cannot merge non-dict "%s" into dict "%s"' % (b, a))
        else:
            raise YamlReaderError('NOT IMPLEMENTED "%s" into "%s"' % (b, a))
    except TypeError, e:
        raise YamlReaderError('TypeError "%s" in key "%s" when merging "%s" into "%s"' % (e, key, b, a))
    return a

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

  • স্কেলারগুলি প্রতিস্থাপন করুন
  • তালিকা যোগ করুন
  • অনুপস্থিত কী যুক্ত করে এবং বিদ্যমান কীগুলি আপডেট করে ডিক্টগুলি মার্জ করুন

অন্য সমস্ত কিছু এবং অপ্রত্যাশিত ফলাফলের ফলে একটি ত্রুটি ঘটে।


1
ফ্যান্টাস্টিক। জেসন ডাম্পগুলিতেও ভাল কাজ করে। সবেমাত্র ত্রুটি পরিচালনার অপসারণ। (অলস হয়ে
উঠতে,

3
"আইসিনস্ট্যান্স" সিকোয়েন্সটি কি ডাব্লু / ইন্টেন 'প্রতিস্থাপন করা isinstance(a, (str, unicode, int, long, float))যায়?
সিমাহক

12

অভিধানের অভিধানগুলি মার্জ করে

যেহেতু এটি প্রচলিত প্রশ্ন (কিছু সাধারণ-সাধারণতা থাকা সত্ত্বেও) আমি এই সমস্যাটি সমাধান করার জন্য ক্যানোনিকাল পাইথোনিক পদ্ধতির সরবরাহ করছি।

সিম্পল কেস: "পাতাগুলি নেস্টেড ডিক্টস যা ফাঁকা ফাঁকে শেষ হয়":

d1 = {'a': {1: {'foo': {}}, 2: {}}}
d2 = {'a': {1: {}, 2: {'bar': {}}}}
d3 = {'b': {3: {'baz': {}}}}
d4 = {'a': {1: {'quux': {}}}}

এটি পুনরাবৃত্তির জন্য সহজতম ঘটনা, এবং আমি দুটি নিষ্পাপ পদ্ধতির সুপারিশ করব:

def rec_merge1(d1, d2):
    '''return new merged dict of dicts'''
    for k, v in d1.items(): # in Python 2, use .iteritems()!
        if k in d2:
            d2[k] = rec_merge1(v, d2[k])
    d3 = d1.copy()
    d3.update(d2)
    return d3

def rec_merge2(d1, d2):
    '''update first dict with second recursively'''
    for k, v in d1.items(): # in Python 2, use .iteritems()!
        if k in d2:
            d2[k] = rec_merge2(v, d2[k])
    d1.update(d2)
    return d1

আমি বিশ্বাস করি যে আমি প্রথমটির চেয়ে দ্বিতীয়টিকে প্রাধান্য দেব, তবে মনে রাখবেন যে প্রথমটির মূল অবস্থানটি এর উত্স থেকেই পুনরায় তৈরি করতে হবে। এখানে ব্যবহার:

>>> from functools import reduce # only required for Python 3.
>>> reduce(rec_merge1, (d1, d2, d3, d4))
{'a': {1: {'quux': {}, 'foo': {}}, 2: {'bar': {}}}, 'b': {3: {'baz': {}}}}
>>> reduce(rec_merge2, (d1, d2, d3, d4))
{'a': {1: {'quux': {}, 'foo': {}}, 2: {'bar': {}}}, 'b': {3: {'baz': {}}}}

জটিল কেস: "পাতাগুলি অন্য কোনও ধরণের:"

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

সুতরাং আরও তথ্যের পরিবর্তে, সহজ পদ্ধতির হ'ল উভয় মানকে ব্যতীত না করা হলে তাদেরকে স্ট্যান্ডার্ড আপডেট চিকিত্সা দেওয়া হবে: দ্বিতীয় ডিকের মান প্রথমটি ওভাররাইট করবে, দ্বিতীয় ডিকের মান কোনওটি না হলেও এবং প্রথমটির মান একটি তথ্য প্রচুর সঙ্গে ডিক।

d1 = {'a': {1: 'foo', 2: None}}
d2 = {'a': {1: None, 2: 'bar'}}
d3 = {'b': {3: 'baz'}}
d4 = {'a': {1: 'quux'}}

from collections import MutableMapping

def rec_merge(d1, d2):
    '''
    Update two dicts of dicts recursively, 
    if either mapping has leaves that are non-dicts, 
    the second's leaf overwrites the first's.
    '''
    for k, v in d1.items(): # in Python 2, use .iteritems()!
        if k in d2:
            # this next check is the only difference!
            if all(isinstance(e, MutableMapping) for e in (v, d2[k])):
                d2[k] = rec_merge(v, d2[k])
            # we could further check types and merge as appropriate here.
    d3 = d1.copy()
    d3.update(d2)
    return d3

এবং এখন

from functools import reduce
reduce(rec_merge, (d1, d2, d3, d4))

আয়

{'a': {1: 'quux', 2: 'bar'}, 'b': {3: 'baz'}}

মূল প্রশ্নের আবেদন:

আমি অক্ষরগুলির চারপাশে কুঁকড়ানো বন্ধনীগুলি সরিয়ে ফেলতে এবং এগুলিকে পাইথন হওয়ার জন্য তাদের একক উদ্ধৃতিতে রেখেছিলাম (অন্যথায় তারা পাইথন ২.7++ তে আক্ষরিক সেট করা হবে) পাশাপাশি একটি অনুপস্থিত বন্ধনী যুক্ত করতে হবে:

dict1 = {1:{"a":'A'}, 2:{"b":'B'}}
dict2 = {2:{"c":'C'}, 3:{"d":'D'}}

এবং rec_merge(dict1, dict2)এখন ফিরে:

{1: {'a': 'A'}, 2: {'c': 'C', 'b': 'B'}, 3: {'d': 'D'}}

মূল প্রশ্ন কাঙ্খিত ফলাফল (পরিবর্তন করার পর, যেমন ম্যাচ {A}থেকে 'A'।)


10

@ অ্যান্ড্রু কুকের উপর ভিত্তি করে এই সংস্করণটি dicts নেস্টেড তালিকা পরিচালনা করে এবং বিকল্পগুলি মান আপডেট করার অনুমতি দেয় update

def merge(a, b, path=None, update=True):
    "http://stackoverflow.com/questions/7204805/python-dictionaries-of-dictionaries-merge"
    "merges b into a"
    if path is None: path = []
    for key in b:
        if key in a:
            if isinstance(a[key], dict) and isinstance(b[key], dict):
                merge(a[key], b[key], path + [str(key)])
            elif a[key] == b[key]:
                pass # same leaf value
            elif isinstance(a[key], list) and isinstance(b[key], list):
                for idx, val in enumerate(b[key]):
                    a[key][idx] = merge(a[key][idx], b[key][idx], path + [str(key), str(idx)], update=update)
            elif update:
                a[key] = b[key]
            else:
                raise Exception('Conflict at %s' % '.'.join(path + [str(key)]))
        else:
            a[key] = b[key]
    return a

1
ধন্যবাদ, এটি এত সহায়ক। আমার কাঠামোগুলিতে আমি সর্বদা ডিক্টের তালিকা রাখছি, অন্যান্য সমাধানগুলি এটি সঠিকভাবে মার্জ করতে পারে না।
শারনান্দেজ

7

এই সাধারণ পুনরাবৃত্তির পদ্ধতিটি বিবাদী কীগুলিকে ওভাররাইড করার সময় একটি অভিধানকে অন্যটিতে মিশে যাবে:

#!/usr/bin/env python2.7

def merge_dicts(dict1, dict2):
    """ Recursively merges dict2 into dict1 """
    if not isinstance(dict1, dict) or not isinstance(dict2, dict):
        return dict2
    for k in dict2:
        if k in dict1:
            dict1[k] = merge_dicts(dict1[k], dict2[k])
        else:
            dict1[k] = dict2[k]
    return dict1

print (merge_dicts({1:{"a":"A"}, 2:{"b":"B"}}, {2:{"c":"C"}, 3:{"d":"D"}}))
print (merge_dicts({1:{"a":"A"}, 2:{"b":"B"}}, {1:{"a":"A"}, 2:{"b":"C"}}))

আউটপুট:

{1: {'a': 'A'}, 2: {'c': 'C', 'b': 'B'}, 3: {'d': 'D'}}
{1: {'a': 'A'}, 2: {'b': 'C'}}

7

@ অ্যান্ড্রু কুকের উত্তরের ভিত্তিতে এটি আরও ভাল উপায়ে নেস্টেড তালিকাগুলির যত্ন নেয়।

def deep_merge_lists(original, incoming):
    """
    Deep merge two lists. Modifies original.
    Recursively call deep merge on each correlated element of list. 
    If item type in both elements are
     a. dict: Call deep_merge_dicts on both values.
     b. list: Recursively call deep_merge_lists on both values.
     c. any other type: Value is overridden.
     d. conflicting types: Value is overridden.

    If length of incoming list is more that of original then extra values are appended.
    """
    common_length = min(len(original), len(incoming))
    for idx in range(common_length):
        if isinstance(original[idx], dict) and isinstance(incoming[idx], dict):
            deep_merge_dicts(original[idx], incoming[idx])

        elif isinstance(original[idx], list) and isinstance(incoming[idx], list):
            deep_merge_lists(original[idx], incoming[idx])

        else:
            original[idx] = incoming[idx]

    for idx in range(common_length, len(incoming)):
        original.append(incoming[idx])


def deep_merge_dicts(original, incoming):
    """
    Deep merge two dictionaries. Modifies original.
    For key conflicts if both values are:
     a. dict: Recursively call deep_merge_dicts on both values.
     b. list: Call deep_merge_lists on both values.
     c. any other type: Value is overridden.
     d. conflicting types: Value is overridden.

    """
    for key in incoming:
        if key in original:
            if isinstance(original[key], dict) and isinstance(incoming[key], dict):
                deep_merge_dicts(original[key], incoming[key])

            elif isinstance(original[key], list) and isinstance(incoming[key], list):
                deep_merge_lists(original[key], incoming[key])

            else:
                original[key] = incoming[key]
        else:
            original[key] = incoming[key]

স্বজ্ঞাত এবং প্রতিসম। তালিকা হ্যান্ডলিংয়ের জন্য +1 :)
ভিডিউইস

6

আপনার যদি অভিধানগুলির একটি অজানা স্তর থাকে তবে আমি একটি পুনরাবৃত্ত ফাংশনটি প্রস্তাব করব:

def combineDicts(dictionary1, dictionary2):
    output = {}
    for item, value in dictionary1.iteritems():
        if dictionary2.has_key(item):
            if isinstance(dictionary2[item], dict):
                output[item] = combineDicts(value, dictionary2.pop(item))
        else:
            output[item] = value
    for item, value in dictionary2.iteritems():
         output[item] = value
    return output

5

সংক্ষিপ্ত বিবরণ

নিম্নলিখিত পদ্ধতির মধ্যে dicts একটি গভীর একত্রীকরণ সমস্যা subdivides:

  1. একটি প্যারামিটারাইজড অগভীর মার্জ ফাংশন merge(f)(a,b)যা fদুটি ডিক্ট aএবং একত্রিত করতে একটি ফাংশন ব্যবহার করেb

  2. fএকসাথে ব্যবহার করার জন্য একটি পুনরাবৃত্ত মার্জার ফাংশনmerge


বাস্তবায়ন

দুটি (অজাতীয়) ডিক্ট মার্জ করার জন্য একটি ফাংশন প্রচুর উপায়ে লেখা যেতে পারে। আমি ব্যক্তিগতভাবে পছন্দ করি

def merge(f):
    def merge(a,b): 
        keys = a.keys() | b.keys()
        return {key:f(a.get(key), b.get(key)) for key in keys}
    return merge

উপযুক্ত পুনরাবৃত্তি সংহত ফাংশন সংজ্ঞায়নের একটি দুর্দান্ত উপায় fহ'ল মাল্টিপ্লেডস্পাচ ব্যবহার করে যা তাদের যুক্তির ধরণের উপর নির্ভর করে বিভিন্ন পাথ ধরে মূল্যায়ন করে এমন ফাংশনগুলি সংজ্ঞায়িত করতে দেয়।

from multipledispatch import dispatch

#for anything that is not a dict return
@dispatch(object, object)
def f(a, b):
    return b if b is not None else a

#for dicts recurse 
@dispatch(dict, dict)
def f(a,b):
    return merge(f)(a,b)

উদাহরণ

দুটি নেস্টেড ডিক্টগুলি মার্জ করার জন্য কেবল merge(f)যেমন:

dict1 = {1:{"a":"A"},2:{"b":"B"}}
dict2 = {2:{"c":"C"},3:{"d":"D"}}
merge(f)(dict1, dict2)
#returns {1: {'a': 'A'}, 2: {'b': 'B', 'c': 'C'}, 3: {'d': 'D'}} 

মন্তব্য:

এই পদ্ধতির সুবিধা হ'ল:

  • ফাংশনটি ছোট ফাংশনগুলি থেকে তৈরি যা প্রতিটি একক কাজ করে যা কোডটি কারণ সম্পর্কে এবং পরীক্ষার জন্য সহজ করে তোলে

  • আচরণটি হার্ড-কোডড নয় তবে প্রয়োজন অনুসারে পরিবর্তিত ও প্রসারিত হতে পারে যা কোডের পুনরায় ব্যবহারের উন্নতি করে (নীচে উদাহরণ দেখুন)।


কাস্টমাইজেশন

কিছু উত্তরে ডিকটকে বিবেচনা করা হয় যা তালিকার অন্তর্ভুক্ত অন্যান্য (সম্ভাব্য নেস্টেড) ডিক্টস। এক্ষেত্রে তালিকাগুলির উপরে মানচিত্রটি চাইতে পারে এবং অবস্থানের ভিত্তিতে সেগুলি মেশানো যেতে পারে। মার্জার ফাংশনে অন্য সংজ্ঞা যুক্ত করে এটি করা যেতে পারে f:

import itertools
@dispatch(list, list)
def f(a,b):
    return [merge(f)(*arg) for arg in itertools.zip_longest(a, b)]

4

যদি কেউ এই সমস্যার আরেকটি উপায় চায় তবে আমার সমাধান এখানে।

গুণাবলী : সংক্ষিপ্ত, ঘোষণামূলক এবং শৈলীতে কার্যকরী (পুনরাবৃত্ত, কোনও রূপান্তর নেই)।

সম্ভাব্য খসড়া : এটি আপনি যে মার্জটি খুঁজছেন তা হতে পারে না। শব্দার্থবিজ্ঞানের জন্য ডক্ট্রিংয়ের পরামর্শ নিন।

def deep_merge(a, b):
    """
    Merge two values, with `b` taking precedence over `a`.

    Semantics:
    - If either `a` or `b` is not a dictionary, `a` will be returned only if
      `b` is `None`. Otherwise `b` will be returned.
    - If both values are dictionaries, they are merged as follows:
        * Each key that is found only in `a` or only in `b` will be included in
          the output collection with its value intact.
        * For any key in common between `a` and `b`, the corresponding values
          will be merged with the same semantics.
    """
    if not isinstance(a, dict) or not isinstance(b, dict):
        return a if b is None else b
    else:
        # If we're here, both a and b must be dictionaries or subtypes thereof.

        # Compute set of all keys in both dictionaries.
        keys = set(a.keys()) | set(b.keys())

        # Build output dictionary, merging recursively values with common keys,
        # where `None` is used to mean the absence of a value.
        return {
            key: deep_merge(a.get(key), b.get(key))
            for key in keys
        }

খুব আকর্ষণীয় উত্তর, ভাগ করে নেওয়ার জন্য আপনাকে ধন্যবাদ। রিটার্ন স্টেটমেন্টের পরে আপনি কোন সিনট্যাক্স ব্যবহার করেছেন? আমি এর সাথে পরিচিত নই।
dev_does_software

4

আপনি একীভূত করার চেষ্টা করতে পারেন


স্থাপন

$ pip3 install mergedeep

ব্যবহার

from mergedeep import merge

a = {"keyA": 1}
b = {"keyB": {"sub1": 10}}
c = {"keyB": {"sub2": 20}}

merge(a, b, c) 

print(a)
# {"keyA": 1, "keyB": {"sub1": 10, "sub2": 20}}

বিকল্পগুলির সম্পূর্ণ তালিকার জন্য, ডক্সগুলি পরীক্ষা করে দেখুন !


3

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

if key in a:
    ...
else:
    a[key] = b[key]

যদি b[key]এটি হয় তবে dictএটি কেবলমাত্র অর্পণ করা হবে aযার অর্থ পরবর্তী কোনও পরিবর্তন যা dictউভয়কেই প্রভাবিত করবে aএবং b

a={}
b={'1':{'2':'b'}}
c={'1':{'3':'c'}}
merge(merge(a,b), c) # {'1': {'3': 'c', '2': 'b'}}
a # {'1': {'3': 'c', '2': 'b'}} (as expected)
b # {'1': {'3': 'c', '2': 'b'}} <----
c # {'1': {'3': 'c'}} (unmodified)

এটি ঠিক করতে, লাইনটি এর সাথে প্রতিস্থাপন করতে হবে:

if isinstance(b[key], dict):
    a[key] = clone_dict(b[key])
else:
    a[key] = b[key]

কোথায় clone_dict:

def clone_dict(obj):
    clone = {}
    for key, value in obj.iteritems():
        if isinstance(value, dict):
            clone[key] = clone_dict(value)
        else:
            clone[key] = value
    return

এখনও। এই স্পষ্টত হিসাব না list, setএবং অন্যান্য উপাদান, কিন্তু আমি আশা করি এটা ফাঁদ প্রকাশ যখন একত্রীকরণ বের করার চেষ্টা dicts

এবং সম্পূর্ণতার জন্য, এখানে আমার সংস্করণ, যেখানে আপনি এটি একাধিক পাস করতে পারেন dicts:

def merge_dicts(*args):
    def clone_dict(obj):
        clone = {}
        for key, value in obj.iteritems():
            if isinstance(value, dict):
                clone[key] = clone_dict(value)
            else:
                clone[key] = value
        return

    def merge(a, b, path=[]):
        for key in b:
            if key in a:
                if isinstance(a[key], dict) and isinstance(b[key], dict):
                    merge(a[key], b[key], path + [str(key)])
                elif a[key] == b[key]:
                    pass
                else:
                    raise Exception('Conflict at `{path}\''.format(path='.'.join(path + [str(key)])))
            else:
                if isinstance(b[key], dict):
                    a[key] = clone_dict(b[key])
                else:
                    a[key] = b[key]
        return a
    return reduce(merge, args, {})

deepcopyতার বদলে কেন হবে না clone_dict?
আরমান্ডো পেরেজ মারকোস

1
কারণ পাইথন স্ট্ডলিব হ'ল বিশাল এবং দুর্দান্ত! আমার এই অস্তিত্বের কোনও চিহ্ন ছিল না - প্লাস কোডটি মজাদার ছোট জিনিস ছিল :-)
এ্যাসেন্স 22:30 '

2

ফাংশনের এই সংস্করণটি অভিধানের সংখ্যা N এবং কেবল অভিধানগুলির জন্য অ্যাকাউন্ট করবে - কোনও অনুপযুক্ত পরামিতিগুলি পাস করা যাবে না, বা এটি টাইপ-এরির উত্থাপন করবে। মার্জ নিজেই মূল দ্বন্দ্বগুলির জন্য অ্যাকাউন্ট করে এবং ডিকশনারি থেকে ডেটা ওভাররাইট করার পরিবর্তে মার্জ শৃঙ্খলে নিচে, এটি মানগুলির একটি সেট তৈরি করে এবং এতে যুক্ত হয়; কোন তথ্য হারিয়ে যায় না।

এটি পৃষ্ঠায় সর্বাধিক কার্যকর নাও হতে পারে তবে এটি সর্বাধিক পুঙ্খানুপুঙ্খ এবং আপনি যখন আপনার 2 এন ডিক্টে মিশে যান তখন কোনও তথ্য হারাবেন না।

def merge_dicts(*dicts):
    if not reduce(lambda x, y: isinstance(y, dict) and x, dicts, True):
        raise TypeError, "Object in *dicts not of type dict"
    if len(dicts) < 2:
        raise ValueError, "Requires 2 or more dict objects"


    def merge(a, b):
        for d in set(a.keys()).union(b.keys()):
            if d in a and d in b:
                if type(a[d]) == type(b[d]):
                    if not isinstance(a[d], dict):
                        ret = list({a[d], b[d]})
                        if len(ret) == 1: ret = ret[0]
                        yield (d, sorted(ret))
                    else:
                        yield (d, dict(merge(a[d], b[d])))
                else:
                    raise TypeError, "Conflicting key:value type assignment"
            elif d in a:
                yield (d, a[d])
            elif d in b:
                yield (d, b[d])
            else:
                raise KeyError

    return reduce(lambda x, y: dict(merge(x, y)), dicts[1:], dicts[0])

print merge_dicts({1:1,2:{1:2}},{1:2,2:{3:1}},{4:4})

আউটপুট: {1: [1, 2], 2: {1: 2, 3: 1}, 4: 4}


2

যেহেতু ডোকিভিউস সেট অপারেশনগুলিকে সমর্থন করে, আমি জেটেরাসের উত্তরকে খুব সহজ করতে সক্ষম হয়েছি।

def merge(dict1, dict2):
    for k in dict1.keys() - dict2.keys():
        yield (k, dict1[k])

    for k in dict2.keys() - dict1.keys():
        yield (k, dict2[k])

    for k in dict1.keys() & dict2.keys():
        yield (k, dict(merge(dict1[k], dict2[k])))

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


2

স্বল্প এন-মিষ্টি:

from collections.abc import MutableMapping as Map

def nested_update(d, v):
"""
Nested update of dict-like 'd' with dict-like 'v'.
"""

for key in v:
    if key in d and isinstance(d[key], Map) and isinstance(v[key], Map):
        nested_update(d[key], v[key])
    else:
        d[key] = v[key]

এটি পাইথনের dict.updateপদ্ধতির মতো (এবং তৈরি হচ্ছে) কাজ করে । এটি ফিরে আসে None(আপনি return dযদি চান তবে আপনি সর্বদা যোগ করতে পারেন ) এটি dস্থানে ডিক আপডেট করে । কীগুলি যে vকোনও বিদ্যমান কীগুলিকে ওভাররাইট করবে d(এটি ডিকের বিষয়বস্তু ব্যাখ্যা করার চেষ্টা করে না)।

এটি অন্যান্য ("ডিক্টের মতো") ম্যাপিংয়ের জন্যও কাজ করবে।


1

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

  • অভিধানগুলি নন-ডিক মানগুলির {"foo": {...}}চেয়ে অগ্রাধিকার নেয় ( অগ্রাধিকার নেয় {"foo": "bar"})
  • পরে আর্গুমেন্ট আগে আর্গুমেন্ট উপর প্রাধান্য (যদি আপনি একত্রীকরণ {"a": 1}, {"a", 2}এবং {"a": 3}জন্য, ফলাফল হবে {"a": 3})
try:
    from collections import Mapping
except ImportError:
    Mapping = dict

def merge_dicts(*dicts):                                                            
    """                                                                             
    Return a new dictionary that is the result of merging the arguments together.   
    In case of conflicts, later arguments take precedence over earlier arguments.   
    """                                                                             
    updated = {}                                                                    
    # grab all keys                                                                 
    keys = set()                                                                    
    for d in dicts:                                                                 
        keys = keys.union(set(d))                                                   

    for key in keys:                                                                
        values = [d[key] for d in dicts if key in d]                                
        # which ones are mapping types? (aka dict)                                  
        maps = [value for value in values if isinstance(value, Mapping)]            
        if maps:                                                                    
            # if we have any mapping types, call recursively to merge them          
            updated[key] = merge_dicts(*maps)                                       
        else:                                                                       
            # otherwise, just grab the last value we have, since later arguments    
            # take precedence over earlier arguments                                
            updated[key] = values[-1]                                               
    return updated  

1

আমার দুটি অভিধান ( aএবং b) ছিল যা প্রত্যেকটিতে নেস্টেড ডিকশনারি থাকতে পারে। আমি bঅগ্রাধিকার গ্রহণের সাথে তাদের পুনরাবৃত্তভাবে মার্জ করতে চেয়েছিলাম a

নেস্টেড অভিধানগুলি গাছ হিসাবে বিবেচনা করে আমি যা চেয়েছিলাম তা হ'ল:

  • আপডেট করার জন্য aযাতে প্রতিটি পাতার প্রতিটি পথই bপ্রতিনিধিত্ব করেa
  • এর মধ্যে aযদি কোনও পাতাকে খুঁজে পাওয়া যায় তবে এর সাবট্রিকে ওভাররাইট করতেb
    • আক্রমণকারীটিকে বজায় রাখুন যে সমস্ত bলিফ নোড পাতা থাকে।

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

  def merge_map(a, b):
    if not isinstance(a, dict) or not isinstance(b, dict):
      return b

    for key in b.keys():
      a[key] = merge_map(a[key], b[key]) if key in a else b[key]
    return a

উদাহরণ (স্বচ্ছতার জন্য ফর্ম্যাট করা):

 a = {
    1 : {'a': 'red', 
         'b': {'blue': 'fish', 'yellow': 'bear' },
         'c': { 'orange': 'dog'},
    },
    2 : {'d': 'green'},
    3: 'e'
  }

  b = {
    1 : {'b': 'white'},
    2 : {'d': 'black'},
    3: 'e'
  }


  >>> merge_map(a, b)
  {1: {'a': 'red', 
       'b': 'white',
       'c': {'orange': 'dog'},},
   2: {'d': 'black'},
   3: 'e'}

যে পথগুলিকে bবজায় রাখা দরকার ছিল তা হ'ল:

  • 1 -> 'b' -> 'white'
  • 2 -> 'd' -> 'black'
  • 3 -> 'e'

a এর অনন্য ও দ্বন্দ্বমূলক পথ ছিল:

  • 1 -> 'a' -> 'red'
  • 1 -> 'c' -> 'orange' -> 'dog'

সুতরাং সেগুলি এখনও মার্জ হওয়া মানচিত্রে উপস্থাপিত হয়।


1

আমার একটি পুনরাবৃত্তি সমাধান রয়েছে - বড় ডিক্টস এবং তাদের অনেকগুলি (উদাহরণস্বরূপ জন্সস ইত্যাদি) এর সাথে অনেক বেশি ভাল কাজ করে:

import collections


def merge_dict_with_subdicts(dict1: dict, dict2: dict) -> dict:
    """
    similar behaviour to builtin dict.update - but knows how to handle nested dicts
    """
    q = collections.deque([(dict1, dict2)])
    while len(q) > 0:
        d1, d2 = q.pop()
        for k, v in d2.items():
            if k in d1 and isinstance(d1[k], dict) and isinstance(v, dict):
                q.append((d1[k], v))
            else:
                d1[k] = v

    return dict1

নোট করুন যে এটি ডি 2-তে ডি 1-কে ওভাররাইড করতে ব্যবহার করবে, যদি তারা উভয় ডিস্ক না হয়। (পাইথনের মতো dict.update())

কিছু পরীক্ষা:

def test_deep_update():
    d = dict()
    merge_dict_with_subdicts(d, {"a": 4})
    assert d == {"a": 4}

    new_dict = {
        "b": {
            "c": {
                "d": 6
            }
        }
    }
    merge_dict_with_subdicts(d, new_dict)
    assert d == {
        "a": 4,
        "b": {
            "c": {
                "d": 6
            }
        }
    }

    new_dict = {
        "a": 3,
        "b": {
            "f": 7
        }
    }
    merge_dict_with_subdicts(d, new_dict)
    assert d == {
        "a": 3,
        "b": {
            "c": {
                "d": 6
            },
            "f": 7
        }
    }

    # test a case where one of the dicts has dict as value and the other has something else
    new_dict = {
        'a': {
            'b': 4
        }
    }
    merge_dict_with_subdicts(d, new_dict)
    assert d['a']['b'] == 4

আমি প্রায় 00 1200 ডিক্ট দিয়ে পরীক্ষা করেছি - এই পদ্ধতিটি 0.4 সেকেন্ড সময় নিয়েছে, যখন পুনরাবৃত্তির সমাধানটি 2.5 ডলারে নিয়েছিল।


0

এই থেকে সকল আইটেম মার্জ মধ্যে সাহায্য করা উচিত dict2মধ্যে dict1:

for item in dict2:
    if item in dict1:
        for leaf in dict2[item]:
            dict1[item][leaf] = dict2[item][leaf]
    else:
        dict1[item] = dict2[item]

দয়া করে এটি পরীক্ষা করুন এবং আপনি যা চেয়েছিলেন এটি এটি কিনা তা আমাদের জানান।

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

উপরের উল্লিখিত সমাধানটি কেবল একটি মাত্রকে একীভূত করে, তবে ওপির দেওয়া উদাহরণটি সঠিকভাবে সমাধান করে। একাধিক স্তর মার্জ করতে, পুনরাবৃত্তিটি ব্যবহার করা উচিত।


1
তিনি পাখির এর একটি অবাধ গভীরতা পেয়েছে
agf

এটি সহজভাবে লিখতে পারেন for k,v in dict2.iteritems(): dict1.setdefault(k,{}).update(v)। কিন্তু @agf যেমন উল্লেখ করেছে, এটি নেস্টেড ডিক্টগুলিকে একীভূত করে না।
শন চিন

@ এএফএফ: সঠিক, সুতরাং মনে হচ্ছে ওপি'র পুনরাবৃত্তি সমাধানের সমাধান দরকার। অভিধানের পরিবর্তে পরিবর্তনীয় হ'ল ধন্যবাদ, এটি করা খুব সহজ হওয়া উচিত। কিন্তু আমি মনে প্রশ্ন নির্দিষ্ট যথেষ্ট বলতে কি, যখন আমরা অতল ভিন্ন মাত্রার সঙ্গে জায়গা নিয়ে আসা ঘটা উচিত (যেমন। একত্রীকরণ বের করার চেষ্টা নয় {'a':'b'}সঙ্গে {'a':{'c':'d'})।
টেডেক

0

আমি আপনার সমাধানগুলি পরীক্ষা করে যাচ্ছি এবং আমার প্রকল্পে এটি ব্যবহার করার সিদ্ধান্ত নিয়েছি:

def mergedicts(dict1, dict2, conflict, no_conflict):
    for k in set(dict1.keys()).union(dict2.keys()):
        if k in dict1 and k in dict2:
            yield (k, conflict(dict1[k], dict2[k]))
        elif k in dict1:
            yield (k, no_conflict(dict1[k]))
        else:
            yield (k, no_conflict(dict2[k]))

dict1 = {1:{"a":"A"}, 2:{"b":"B"}}
dict2 = {2:{"c":"C"}, 3:{"d":"D"}}

#this helper function allows for recursion and the use of reduce
def f2(x, y):
    return dict(mergedicts(x, y, f2, lambda x: x))

print dict(mergedicts(dict1, dict2, f2, lambda x: x))
print dict(reduce(f2, [dict1, dict2]))

অন্যান্য সমস্ত পুনরাবৃত্ত সমাধান হিসাবে আচরণ করার জন্য জেটেরেস সমাধানটি প্রসারিত করার জন্য প্যারামিটার হিসাবে ফাংশনগুলি পাস করা গুরুত্বপূর্ণ।


0

সবচেয়ে সহজ উপায় আমি এটি ভাবতে পারি:

#!/usr/bin/python

from copy import deepcopy
def dict_merge(a, b):
    if not isinstance(b, dict):
        return b
    result = deepcopy(a)
    for k, v in b.iteritems():
        if k in result and isinstance(result[k], dict):
                result[k] = dict_merge(result[k], v)
        else:
            result[k] = deepcopy(v)
    return result

a = {1:{"a":'A'}, 2:{"b":'B'}}
b = {2:{"c":'C'}, 3:{"d":'D'}}

print dict_merge(a,b)

আউটপুট:

{1: {'a': 'A'}, 2: {'c': 'C', 'b': 'B'}, 3: {'d': 'D'}}

0

আমার এখানে আরও কিছুটা আলাদা সমাধান রয়েছে:

def deepMerge(d1, d2, inconflict = lambda v1,v2 : v2) :
''' merge d2 into d1. using inconflict function to resolve the leaf conflicts '''
    for k in d2:
        if k in d1 : 
            if isinstance(d1[k], dict) and isinstance(d2[k], dict) :
                deepMerge(d1[k], d2[k], inconflict)
            elif d1[k] != d2[k] :
                d1[k] = inconflict(d1[k], d2[k])
        else :
            d1[k] = d2[k]
    return d1

ডিফল্টরূপে এটি দ্বিতীয় ডিকের মানগুলির পক্ষে দ্বন্দ্বগুলি সমাধান করে তবে আপনি সহজেই এটিকে ওভাররাইড করতে পারেন, কিছু জাদুকরী দ্বারা আপনি এর ব্যতিক্রমগুলি ছুঁড়ে ফেলতেও সক্ষম হতে পারেন। :)।


0
class Utils(object):

    """

    >>> a = { 'first' : { 'all_rows' : { 'pass' : 'dog', 'number' : '1' } } }
    >>> b = { 'first' : { 'all_rows' : { 'fail' : 'cat', 'number' : '5' } } }
    >>> Utils.merge_dict(b, a) == { 'first' : { 'all_rows' : { 'pass' : 'dog', 'fail' : 'cat', 'number' : '5' } } }
    True

    >>> main = {'a': {'b': {'test': 'bug'}, 'c': 'C'}}
    >>> suply = {'a': {'b': 2, 'd': 'D', 'c': {'test': 'bug2'}}}
    >>> Utils.merge_dict(main, suply) == {'a': {'b': {'test': 'bug'}, 'c': 'C', 'd': 'D'}}
    True

    """

    @staticmethod
    def merge_dict(main, suply):
        """
        获取融合的字典,以main为主,suply补充,冲突时以main为准
        :return:
        """
        for key, value in suply.items():
            if key in main:
                if isinstance(main[key], dict):
                    if isinstance(value, dict):
                        Utils.merge_dict(main[key], value)
                    else:
                        pass
                else:
                    pass
            else:
                main[key] = value
        return main

if __name__ == '__main__':
    import doctest
    doctest.testmod()

0

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

#used to copy a nested dict to a nested dict
def deepupdate(target, src):
    for k, v in src.items():
        if k in target:
            for k2, v2 in src[k].items():
                if k2 in target[k]:
                    target[k][k2]+=v2
                else:
                    target[k][k2] = v2
        else:
            target[k] = copy.deepcopy(v)

উপরের পদ্ধতিটি ব্যবহার করে আমরা মার্জ করতে পারি:

লক্ষ্য = {'6,6': {'6,63': 1}, '63, 4 ': 4' 4,4 ': 1},' 4,4 ': 4' 4,3 ': 1 , '6,63': {'63, 4 ': 1}

src = {'5,4': {'4,4': 1}, '5,5': {'5,4': 1}, '4,4': 4 '4,3': 1 }

এবং এটি হয়ে যাবে: {'5,5': {'5,4': 1}, '5,4': {'4,4': 1 ',' 6,6 ': 6' 6,63 ' : 1}, '63, 4 ': 4' 4,4 ': 1},' 4,4 ': {' 4,3 ': 2},' 6,63 ': {'63, 4': 1 }}

এখানে পরিবর্তনগুলি লক্ষ্য করুন:

টার্গেট = { '6,6': { '6,63': 1}, '6,63': {'63, 4 ': 1}, ' 4,4 ': {' 4,3 ': 1} , '63, 4 ': {' 4,4 ': 1}

src = {'5,4': {'4,4': 1}, '4,3': 3, '3,4': 1}, '4,4': 4 '4,9': 1 , '3,4': {'4,4': 1}, '5,5': {'5,4': 1}

মার্জ = {'5,4': {'4,4': 1}, '4,3': 3, '3,4': 1}, '6,63': {'63, 4 ': 1} , '5,5': {'5,4': 1}, '6,6': {'6,63': 1}, '3,4': {'4,4': 1}, ' 63,4 ': {' 4,4 ': 1}, ' 4,4 ': {' 4,3 ': 1,' 4,9 ': 1 }

কপির জন্য আমদানি যুক্ত করতে ভুলবেন না:

import copy

0
from collections import defaultdict
from itertools import chain

class DictHelper:

@staticmethod
def merge_dictionaries(*dictionaries, override=True):
    merged_dict = defaultdict(set)
    all_unique_keys = set(chain(*[list(dictionary.keys()) for dictionary in dictionaries]))  # Build a set using all dict keys
    for key in all_unique_keys:
        keys_value_type = list(set(filter(lambda obj_type: obj_type != type(None), [type(dictionary.get(key, None)) for dictionary in dictionaries])))
        # Establish the object type for each key, return None if key is not present in dict and remove None from final result
        if len(keys_value_type) != 1:
            raise Exception("Different objects type for same key: {keys_value_type}".format(keys_value_type=keys_value_type))

        if keys_value_type[0] == list:
            values = list(chain(*[dictionary.get(key, []) for dictionary in dictionaries]))  # Extract the value for each key
            merged_dict[key].update(values)

        elif keys_value_type[0] == dict:
            # Extract all dictionaries by key and enter in recursion
            dicts_to_merge = list(filter(lambda obj: obj != None, [dictionary.get(key, None) for dictionary in dictionaries]))
            merged_dict[key] = DictHelper.merge_dictionaries(*dicts_to_merge)

        else:
            # if override => get value from last dictionary else make a list of all values
            values = list(filter(lambda obj: obj != None, [dictionary.get(key, None) for dictionary in dictionaries]))
            merged_dict[key] = values[-1] if override else values

    return dict(merged_dict)



if __name__ == '__main__':
  d1 = {'aaaaaaaaa': ['to short', 'to long'], 'bbbbb': ['to short', 'to long'], "cccccc": ["the is a test"]}
  d2 = {'aaaaaaaaa': ['field is not a bool'], 'bbbbb': ['field is not a bool']}
  d3 = {'aaaaaaaaa': ['filed is not a string', "to short"], 'bbbbb': ['field is not an integer']}
  print(DictHelper.merge_dictionaries(d1, d2, d3))

  d4 = {"a": {"x": 1, "y": 2, "z": 3, "d": {"x1": 10}}}
  d5 = {"a": {"x": 10, "y": 20, "d": {"x2": 20}}}
  print(DictHelper.merge_dictionaries(d4, d5))

আউটপুট:

{'bbbbb': {'to long', 'field is not an integer', 'to short', 'field is not a bool'}, 
'aaaaaaaaa': {'to long', 'to short', 'filed is not a string', 'field is not a bool'}, 
'cccccc': {'the is a test'}}

{'a': {'y': 20, 'd': {'x1': 10, 'x2': 20}, 'z': 3, 'x': 10}}

এই কোডটি প্রশ্নের উত্তর দিতে পারে, কেন এবং / অথবা এই কোডটির প্রশ্নের উত্তর কীভাবে তার দীর্ঘমেয়াদী মানকে উন্নত করে সে সম্পর্কে অতিরিক্ত প্রসঙ্গ সরবরাহ করে।
xiawi

আমি মনে করি এটি যে একাধিক নেস্টেড ডিকশনারি মার্জ করা হবে তার ধরণের বিবেচনা করে মার্জ করার একটি সাধারণ বাস্তবায়ন
ডরসিওম্যান

0

প্যাকেজ একবার দেখুনtoolz

import toolz
dict1={1:{"a":"A"},2:{"b":"B"}}
dict2={2:{"c":"C"},3:{"d":"D"}}
toolz.merge_with(toolz.merge,dict1,dict2)

দেয়

{1: {'a': 'A'}, 2: {'b': 'B', 'c': 'C'}, 3: {'d': 'D'}}


0

এবং অন্য একটি সামান্য প্রকরণ:

এখানে একটি খাঁটি পাইথন 3 সেট ভিত্তিক গভীর আপডেট ফাংশন রয়েছে। এটি একবারে এক স্তরকে লুপ করে নেস্টেড ডিকশনারিগুলি আপডেট করে এবং অভিধানের প্রতিটি স্তরের মানগুলিকে আপডেট করার জন্য নিজেকে কল করে:

def deep_update(dict_original, dict_update):
    if isinstance(dict_original, dict) and isinstance(dict_update, dict):
        output=dict(dict_original)
        keys_original=set(dict_original.keys())
        keys_update=set(dict_update.keys())
        similar_keys=keys_original.intersection(keys_update)
        similar_dict={key:deep_update(dict_original[key], dict_update[key]) for key in similar_keys}
        new_keys=keys_update.difference(keys_original)
        new_dict={key:dict_update[key] for key in new_keys}
        output.update(similar_dict)
        output.update(new_dict)
        return output
    else:
        return dict_update

একটি সহজ উদাহরণ:

x={'a':{'b':{'c':1, 'd':1}}}
y={'a':{'b':{'d':2, 'e':2}}, 'f':2}

print(deep_update(x, y))
>>> {'a': {'b': {'c': 1, 'd': 2, 'e': 2}}, 'f': 2}

0

আর কি উত্তর হবে?!? এই এক পরিবর্তন বা পার্শ্ব প্রতিক্রিয়া এড়ানো:

def merge(dict1, dict2):
    output = {}

    # adds keys from `dict1` if they do not exist in `dict2` and vice-versa
    intersection = {**dict2, **dict1}

    for k_intersect, v_intersect in intersection.items():
        if k_intersect not in dict1:
            v_dict2 = dict2[k_intersect]
            output[k_intersect] = v_dict2

        elif k_intersect not in dict2:
            output[k_intersect] = v_intersect

        elif isinstance(v_intersect, dict):
            v_dict2 = dict2[k_intersect]
            output[k_intersect] = merge(v_intersect, v_dict2)

        else:
            output[k_intersect] = v_intersect

    return output
dict1 = {1:{"a":{"A"}}, 2:{"b":{"B"}}}
dict2 = {2:{"c":{"C"}}, 3:{"d":{"D"}}}
dict3 = {1:{"a":{"A"}}, 2:{"b":{"B"},"c":{"C"}}, 3:{"d":{"D"}}}

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