Python中合并不同列表中的字典

4

我需要合并两个包含字典的列表:

dict1 = [{'Count': '307', 'name': 'Other', 'Percentage': '7.7%'}, {'Count': '7,813', 'name': 'Other', 'Percentage': '6.8%'}...]
dict2 = [{'Place': 'Home'}, {'Place':'Forest'},...]

第一个列表(56个字典)中有56个元素,第二个列表(dict2)中有14个元素。我想做的是将dict2的第一个元素插入到dict1的前四个元素中,并重复此过程,直到dict1中所有56个元素都具有{Place:x}。
所以最终我想得到的是:
newdict = [{'Count': '307', 'name': 'Other', 'Percentage': '7.7%', 'Place': 'Home'}, {'Count': '7,813', 'name': 'Other', 'Percentage': '6.8%', 'Place':'Home'},{'Name': 'Other', 'Percentage': '6.6%', 'Place': 'Home', 'Count': '1,960'},{'Name': 'Other', 'Percentage': '7.6%', 'Place': 'Home', 'Count': '1,090'},{'Name': 'Other', 'Percentage': '7.6%', 'Place': 'Forest', 'Count': '1,090'} ]
等等。
当dict2用尽时,它应该重新从第一个元素开始。
因此,我更新了问题。我对这个问题的第一次尝试是增加dict2中相同键:值的数量:
dict2 = [{'Place': 'Home'}, {'Place':'Home'},{'Place':'Home'},{'Place':'Home'},{'Place':'Forest'},{'Place':'Forest'}...]
然后使用下面提到的相同方法合并字典。但我相信应该有一种方法可以在不更改dict2的情况下完成这个操作。

2
第二个列表用尽后,第一个列表的第十五个元素应该发生什么? - Patrick Haugh
你的 dict2 只有14个元素,当我们处理 dict1 中的第15个元素时会发生什么? - Willem Van Onsem
它应该从字典2的第一个元素重新开始。 - Extria
你尝试过什么吗? - depperm
dict1dict2不是用于表示列表的好名称。 - Chris_Rands
4个回答

7
我们将使用zipitertools.cycle来将两个列表中的元素配对。
from itertools import cycle

for a, b in zip(dict1, cycle(dict2)):
    a.update(b)

如果您不想修改原始列表,这会稍微复杂一些。

from itertools import cycle, chain

new_list = [{k:v for k, v in chain(a.items(), b.items())} for a, b in zip(dict1, cycle(dict2))]

这会改变最初给定的字典,我不知道这是否是期望的行为。尽管如此,加一分。 - Willem Van Onsem
2
如果你想要建立一个新的列表... [dict(a,**b) for a, b in zip(dict1, cycle(dict2))] - Chris_Rands
@Chris_Rands 更好!我尝试了dict(**a, **b),但在我使用的Python版本上无效,所以我选择放弃,转而使用itertools。 - Patrick Haugh
@PatrickHaugh 能否解释一下第二个脚本是如何工作的吗?我不明白 k:v for k, v in chain.from_iterable([a.items(), b.items()])} 中的 k:v 是做什么的?虽然它运行得很完美,但我就是不理解它的原理。 - Extria
1
@Extria 确定。这是一个字典推导式,它是一种从现有数据构建字典的方法。items是字典的一种方法,返回键值对作为元组列表。chain.from_iterable获取子可迭代对象的可迭代对象(这里是列表的列表),并产生第一个子可迭代对象的所有元素,然后是第二个子可迭代对象。基本上,我们在这里所做的就是通过组合我们已经拥有的两个字典来创建一个新的字典。 - Patrick Haugh

0

那么,我们可以简单地创建一个名为result的空字典,并将要合并的现有字典列表更新到其中,例如:

def merge_dicts(*dict_args):
    """
    Given any number of dicts, shallow copy and merge into a new dict,
    precedence goes to key value pairs in latter dicts.
    :param dict_args: a list of dictionaries
    :return: dict - the merged dictionary
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result

谢谢您的回答,但这种方法无法得到我想要的结果。我想要的是将列表dict2中的第一个字典更新到列表dict1的前四个字典中,然后将列表dict2中的第二个字典更新到列表dict1的第4-8个字典中,以此类推。 - Extria

0
你可以使用 zip()
res = []

for i, j in zip(dict1, dict2):
    res.append(i)
    res[-1].update(j)

如果你的字典中的项目数量不相同,你可以使用itertools.izip_longest()函数,并将fillvalue参数设置为{}
res = []

for i, j in itertools.izip_longest(dict1, dict2, fillvalue={}):
    res.append(i)
    res[-1].update(j)

1
列表推导式怎么样:[dict(x,**y) for x,y in zip(dict1,dict2)] - Chris_Rands
@Chris_Rands 那是个很好的选择! - ettanany

0

使用取模运算符:

new_list = []
x = len(dict2)
for v, item in enumerate(dict1):
    z = item.copy()
    z['Place'] = dict2[v % x]['Place']
    new_list.append(z)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接