tbicr
tbicr

Reputation: 26070

How merge with appending two nested dictionaries in python?

For example I have two dicts:

schema = {
    'type': 'object',
    'properties': {
        'reseller_name': {
            'type': 'string',
        },
        'timestamp': {
            'type': 'integer',
        },
    },
    'required': ['reseller_name', 'timestamp'],
}

and

schema_add = {
    'properties': {
        'user_login': {
            'type': 'string',
        },
    },
    'required': ['user_login'],
}

How I can get next merged with appending result dict:

schema_result = {
    'type': 'object',
    'properties': {
        'reseller_name': {
            'type': 'string',
        },
        'timestamp': {
            'type': 'integer',
        },
        'user_login': {
            'type': 'string',
        },
    },
    'required': ['reseller_name', 'timestamp', 'user_login'],
}

Rules:

Same path is properties and required for scheme and scheme_add in example.

  1. If both dict have dicts with same path, they merged with same rules.
  2. If both dict have lists with same path, then add first list with second.
  3. If both dict have simple values (or dict and non dict or list and non list) with same path, then first value overriding with second.
  4. If only one dict have key with some path, than setting this key and value.

Upvotes: 1

Views: 1307

Answers (4)

fakhir hanif
fakhir hanif

Reputation: 655

Try this if you know the keys exactly.

schema['properties'].update(schema_add['properties'])
schema['result'].append(schema_add['result'])

result is merged in schema.

If you do not know the keys exactly then one loop is required to find inner list and dictionaries.

for value in schema:
    if value is dict:
        if schema_add.has_key(value) and schema_add[value] is dict:
            schema[value].update(schema_add[value])
    elif value is list:
        if schema_add.has_key(value) and schema_add[value] is list:
            schema[value].append(schema_add[value])

result can be merged into different dict as well.

Upvotes: 0

Abdul Majeed
Abdul Majeed

Reputation: 2781

I am adding simple solution of this problem. Assuming that sample data will not change.

def merge_nested_dicts(schema,schema_add):
    new_schema = schema
    for k in schema:
        if k in schema_add.keys():
            if isinstance(schema_add[k],dict):
                new_schema[k].update(schema_add[k])
            if isinstance(schema_add[k],list):
                new_schema[k] = new_schema[k]+schema_add[k]
    return new_schema

Upvotes: 2

tbicr
tbicr

Reputation: 26070

My own solution with @Nicolas78 help:

def merge(obj_1, obj_2):
    if type(obj_1) == dict and type(obj_2) == dict:
        result = {}
        for key, value in obj_1.iteritems():
            if key not in obj_2:
                result[key] = value
            else:
                result[key] = merge(value, obj_2[key])
        for key, value in obj_2.iteritems():
            if key not in obj_1:
                result[key] = value
        return result
    if type(obj_1) == list and type(obj_2) == list:
        return obj_1 + obj_2
    return obj_2

Upvotes: 2

Nicolas78
Nicolas78

Reputation: 5144

Not sure where the problem likes, but the way you're writing it down is almost like a computer program, and the example is like a test case. Why don't you start from this?

def add_dict(d1, d2):
    newdict = {}
    for (key, value) in d1.iteritems():
        if key in d2: ...
            #apply rules, add to newdict, use 
        else:
            #simply add
    for (key, value) in d2.iteritems():
        if not key in d1:
            # simply add
    return newdict

This can probably be written more tightly, but might be easier like that to edit.

Edit.. after writing the last comment, couldn't help but write a nicer implementation

def merge_values(a,b):
    if a==None or b==None:
        return a or b
    # now handle cases where both have values
    if type(a)==dict:
        return add_dict(a, b)
    if type(a)==list:
        ...

def add_dict(d1,d2):
    return dict(
        [
            (key,
             merge_values(
                 d1.get(key,None),
                 d2.get(key,None)))
            for key
            in set(d1.keys()).union(d2.keys())
        ])

Upvotes: 2

Related Questions