如何合并具有重复值的字典列表以创建嵌套字典?

时间:2019-11-29 13:17:10

标签: python

我有一个形式的字典:

[
    {
        "group_name": "CUSTOMER_RED",
        "interface": "ae4",
        "unit_name": 2520
    },
    {
        "group_name": "CUSTOMER_RED",
        "interface": "ae4",
        "unit_name": 4091
    },
    {
        "group_name": "CUSTOMER_BLUE",
        "interface": "ae4",
        "unit_name": 847
    },
    {
        "group_name": "CUSTOMER_BLUE",
        "interface": "ae4",
        "unit_name": 103
    }
}

如何合并它以形成一个列表,如:

[
    {
        "group_name": "CUSTOMER_RED",
        "interface": "ae4",
        "unit_names": [2520, 4091]
    },
    {
        "group_name": "CUSTOMER_BLUE",
        "interface": "ae4",
        "unit_names": [847, 103]
    },
}

或者更简单:

[
    {
        "group_name": "CUSTOMER_RED",
        "interfaces": ["ae4": "unit_names": [2520, 4091]]
    },
    {
        "group_name": "CUSTOMER_BLUE",
        "interface": ["ae4": "unit_names": [847, 103]]
    },
}

我尝试过:

def merge_relevant_config(config):
    return_config = []
    for item in config:
        name = item['group_name']
        interface = item['interface']
        units = []
        for item in config:
            if item['group_name'] == name and item['interface'] == interface:
                units.append(item['unit_name'])
        return_config.append({
            'name': name,
            'interface': interface,
            'units': units
        })
    return return_config

但是返回的结果却令人失望:

[
    {
        "name": "CUSTOMER_RED",
        "interface": "ae4",
        "units": [
            2520,
            4091
        ]
    },
    {
        "name": "CUSTOMER_RED",
        "interface": "ae4",
        "units": [
            2520,
            4091
        ]
    },
    {
        "name": "CUSTOMER_BLUE",
        "interface": "ae4",
        "units": [
            847,
            103
        ]
    },
    {
        "name": "CUSTOMER_BLUE",
        "interface": "ae4",
        "units": [
            847,
            103
        ]
    }
]

4 个答案:

答案 0 :(得分:6)

这是一种方法。

例如:

data = [
    {
        "group_name": "CUSTOMER_RED",
        "interface": "ae4",
        "unit_name": 2520
    },
    {
        "group_name": "CUSTOMER_RED",
        "interface": "ae4",
        "unit_name": 4091
    },
    {
        "group_name": "CUSTOMER_BLUE",
        "interface": "ae4",
        "unit_name": 847
    },
    {
        "group_name": "CUSTOMER_BLUE",
        "interface": "ae4",
        "unit_name": 103
    }
]

result = {}
for i in data:
    if i['group_name'] not in result:
        #if group by `group_name` & `interface` use --> result[(i['group_name'], i['interface'])]
        result[i['group_name']] = {'group_name': i['group_name'], 'interface': i['interface'], "unit_names": [i['unit_name']]}
    else:
        result[i['group_name']]["unit_names"].append(i['unit_name'])

print(list(result.values()))

输出:

[
    {
        'group_name': 'CUSTOMER_RED',
        'interface': 'ae4',
        'unit_names': [2520, 4091]
    },
    {
        'group_name': 'CUSTOMER_BLUE',
        'interface': 'ae4',
        'unit_names': [847, 103]
    }
]

答案 1 :(得分:1)

另一个答案不考虑多个接口,此示例可以:

def merge_config(config):
    merged = []
    sets = {}
    for item in config:
        as_text = '{}-{}'.format(item['group_name'], item['interface'])
        if as_text in sets.keys():
            sets[as_text].append(item['unit_name'])
        else:
            sets[as_text] = [item['unit_name']]

    for k, v in sets.items():
        group_name, interface = k.split('-')
        merged.append(
            {
                'group_name': group_name,
                'interface': interface,
                'unit_names': v
            }
        )
   return merged

答案 2 :(得分:0)

这里有一个使用itertools.groupy和自定义函数的多功能功能。您可以定义要分组的键,而无需知道内部键,您仍然可以完全合并字典:

from itertools import groupby

def merge_dicts(*dcts):
    # define a merge function
    merged = {}
    for dct in dcts:
        for k, v in dct.items():            
            if merged.setdefault(k, v) != v:
                if not isinstance(merged.get(k), list):
                    merged[k] = [merged.get(k)]
                merged.get(k).append(v)
    return merged

group_key = 'group_name'
result = [merge_dicts(*grouped) for key, grouped in groupby(l, lambda dct: dct.get(group_key))]

输出:

[
  {
    'group_name': 'CUSTOMER_RED',
    'interface': 'ae4',
    'unit_name': [2520, 4091]
  },
  {
    'group_name': 'CUSTOMER_BLUE',
    'interface': 'ae4',
    'unit_name': [847, 103]
  }
]

答案 3 :(得分:0)

要完全结合所有常用键,可以将递归与itertools.groupby一起使用:

from itertools import groupby as gb
data = [{'group_name': 'CUSTOMER_RED', 'interface': 'ae4', 'unit_name': 2520}, {'group_name': 'CUSTOMER_RED', 'interface': 'ae4', 'unit_name': 4091}, {'group_name': 'CUSTOMER_BLUE', 'interface': 'ae4', 'unit_name': 847}, {'group_name': 'CUSTOMER_BLUE', 'interface': 'ae4', 'unit_name': 103}]
def group(d):
   _d = [(a, list(b)) for a, b in gb(sorted(d, key=lambda x:x[0]), key=lambda x:x[0])]
   return [b if not (j:=[l for i in k if (l:=i[1:])]) else {a:{b:group(j)}} for (a, b), k in _d]

print(group([list(i.items()) for i in data]))

输出:

[{'group_name': {'CUSTOMER_BLUE': [{'interface': {'ae4': [103, 847]}}]}}, {'group_name': {'CUSTOMER_RED': [{'interface': {'ae4': [2520, 4091]}}]}}]