Python 3.x 将字典列表与公共键合并,而不合并值

Python 3.x 将字典列表与公共键合并,而不合并值,python-3.x,Python 3.x,我有多个字典列表,如下所示: data_aus = [{'name': '2018,7', 'aus_ct': 13}, {'name': '2018,8', 'aus_ct': 3}, {'name': '2018,9', 'aus_ct': 3}] data_asia = [{'name': '2018,7', 'asia_ct': 10}, {'name': '2018,8', 'asia_ct': 11}, {'name': '2018,9', 'asia_ct': 6}] dat

我有多个字典列表,如下所示:

data_aus =
[{'name': '2018,7', 'aus_ct': 13}, {'name': '2018,8', 'aus_ct': 3}, {'name': '2018,9', 'aus_ct': 3}]

data_asia = 
[{'name': '2018,7', 'asia_ct': 10}, {'name': '2018,8', 'asia_ct': 11}, {'name': '2018,9', 'asia_ct': 6}]

data_us =
[{'name': '2018,7', 'us_ct': 5}, {'name': '2018,8', 'us_ct': 8}, {'name': '2018,9', 'us_ct': 9}, {'name': '2018,10', 'us_ct': 23}]

data_uk =
[{'name': '2018,7', 'uk_ct': 15}, {'name': '2018,8', 'uk_ct': 7}, {'name': '2018,9', 'uk_ct': 13}]
我想根据一个名为
name
的公用键,将这些列表合并成一个字典列表

结果应该如下所示:

data_combined = [
{'name': '2018,7', 'aus_ct': 13, 'asia_ct': 10, 'us_ct': 5, 'uk_ct':15},
{'name': '2018,8', 'aus_ct': 3, 'asia_ct': 11, 'us_ct': 8, 'uk_ct':7},
...]
有没有一个简单的方法可以做到这一点?请帮助。

1)将所有数据准备到一个列表中,并在数据中查找所有可用月份

# Put all data into a single list
all_data = [month_data for country_data in [data_aus, data_asia, data_us, data_uk] for month_data in country_data]

# Figure out the months available
months = set(map(lambda entry: entry['name'], all_data))
2) 通过逐月迭代并通过字典将数据合并

data_combined = []
# Iterate month by month
for month in months:

    # Get all the data from a single month (list of dicts)
    month_data = filter(lambda entry: entry['name'] == month, all_data)

    # "Tricky part" merge the list of dictionaries
    sigle_month_data = {k: v for d in month_data for k, v in d.items()}

    # Append to the overall combined list
    data_combined.append(single_month_data)
3) 结果

尝试#1

编辑:如果键的顺序不同,则编辑失败

通过创建一个函数来合并任意数量的词典,实现了此解决方案:

from itertools import zip_longest

def merge_dicts(dicts):
    result = []
    for d in dicts:
        result = [{**u, **v} for u, v in zip_longest(result, d, fillvalue={})]

    return result
并将所有列表作为输入传递:

merge_dicts([data_aus, data_asia, data_us, data_uk])
输出为:

    [
      {
        "name": "2018,8",
        "aus_ct": 5,
        "asia_ct": 5,
        "us_ct": 8,
        "uk_ct": 9
      },
      {
        "name": "2018,9",
        "aus_ct": 2,
        "asia_ct": 1,
        "us_ct": 2,
        "uk_ct": 6
      },
      {
        "name": "2018,10",
        "aus_ct": 3,
        "asia_ct": 1,
        "us_ct": 3,
        "uk_ct": 11
      },
      {
        "name": "2018,11",
        "aus_ct": 9,
        "asia_ct": 1,
        "us_ct": 1,
        "uk_ct": 1
      },
      {
        "name": "2019,6",
        "aus_ct": 7,
        "us_ct": 1,
        "uk_ct": 2
      },
      {
        "name": "2019,8",
        "aus_ct": 7,
        "uk_ct": 1
      },
      {
        "name": "2019,1",
        "aus_ct": 2
      },
      {
        "name": "2019,3",
        "aus_ct": 2
      },
      {
        "name": "2019,4",
        "aus_ct": 1
      },
      {
        "name": "2019,5",
        "aus_ct": 4
      },
      {
        "name": "2019,6",
        "aus_ct": 4
      },
      {
        "name": "2019,7",
        "aus_ct": 3
      },
      {
        "name": "2019,8",
        "aus_ct": 2
      },
      {
        "name": "2019,9",
        "aus_ct": 1
      },
      {
        "name": "2019,10",
        "aus_ct": 1
      }
    ]
谢谢你的回复。让我知道在性能方面是否有更好的方法

尝试#2

我想这应该行得通:

import itertools
from collections import defaultdict

def merge_dicts(shared_key, *dicts):
    # Remove empty dicts (if any)
    dicts = list(filter(None, dicts))

    # Merging dicts based on shared keys
    result = defaultdict(dict)
    for dictionary in itertools.chain.from_iterable(dicts):
        result[dictionary[shared_key]].update(dictionary)

    # And converting results from {key1: dict1, key2: dict2, ...} to list of dicts [dict1, dict2, ...]
    return list(result.values())
打电话给

merge_dicts('name', data_aus, data_asia, data_us, data_uk)

如果这种方法有任何问题,请告诉我。

您的代码在哪里?这些名称下列出的变量是
数据?
还是您给了每个变量一个名称?谢谢,但我找到了一种更简单的方法。@saran3h当然,没问题。我想这将取决于你对“更简单”的定义。)两种解决方案都有7行代码…:要使您的输出具有代表性和意义,它应该与您的初始输入相关联,但事实并非如此。现在看来,我不明白你的意思,但这正是我想要的。如果你指的是与我在这个问题中不匹配的值,当然它们不是实际数据的代表,而是用来传达意义的。这种方法根本不考虑你的条件“基于一个叫做“代码>名字<代码>的共同密钥”。如果任何dict中项目的顺序发生变化,以及dict(条目)中键的顺序不同,则不会产生正确的结果。这不是解决方案,所以,看看你原来的问题,你已经得到了预期的结果:
{name':'2018,8','aus_-ct':3,'asia_-ct':11,'us_-ct':8,'uk_-ct':7}
,但在你的回答中你有
{“name:'2018,8”,“aus_-ct:'5,'asia_-ct':5,'us_-ct':8,'uk u-ct':9}
。确保你得到了正确的结果…@bruno正如我上面所说的,这些值是任意表达意思的。
merge_dicts('name', data_aus, data_asia, data_us, data_uk)