多个词典列表的笛卡尔积

时间:2016-05-03 20:30:21

标签: python list python-3.x dictionary itertools

我有两个或更多字典,每个字典都是字典列表(类似于json格式),例如:

list_1 = [{'Name': 'John' , 'Age': 25} , {'Name': 'Mary' , 'Age': 15}]
list_2 = [{'Product': 'Car', 'Id': 1} , {'Product': 'TV' , 'Id': 2}]
cartesian_product(list_1 * list_2) = [{'Name': 'John', 'Age':25, 'Product': 'Car', 'Id': 1}, {'Name': 'John', 'Age':25, 'Product': 'TV', 'Id': 2}, {'Name': 'Mary' , 'Age': 15, 'Product': 'Car', 'Id': 1}, {'Name': 'Mary' , 'Age': 15, 'Product': 'TV', 'Id': 2}]

我如何做到这一点,并在内存使用方面高效?我现在这样做的方式已经耗尽了大量列表的RAM。我知道它可能与itertools.product有关,但我无法弄清楚如何使用一系列dicts来做到这一点。谢谢。

PD:我现在这样做:

gen1 = (row for row in self.tables[0])
table = []
for row in gen1:
    gen2 = (dictionary for table in self.tables[1:] for dictionary in table)
    for element in gen2:
         new_row = {}
         new_row.update(row)
         new_row.update(element)
         table.append(new_row)

谢谢!

3 个答案:

答案 0 :(得分:0)

以下是发布问题的解决方案:

list_1 = [{'Name': 'John' , 'Age': 25} , {'Name': 'Mary' , 'Age': 15}]
list_2 = [{'Product': 'Car', 'Id': 1} , {'Product': 'TV' , 'Id': 2}]


from itertools import product
ret_list = []
for i1, i2 in product(list_1, list_2):
    merged = {}
    merged.update(i1)
    merged.update(i2)
    ret_list.append(merged)

此处的关键是利用update的{​​{1}}功能添加成员。此版本将保留父级dicts未修改。并且会默默地删除重复键,以支持最后看到的任何内容。

但是,这对内存使用没有帮助。简单的事实是,如果要在内存中执行此操作,则需要能够存储起始列表和生成的产品。替代方案包括定期写入磁盘或将起始数据分成块并随时删除块。

答案 1 :(得分:0)

只需将词典转换为列表,获取产品,然后再返回字典:

import itertools

list_1 = [{'Name': 'John' , 'Age': 25} , {'Name': 'Mary' , 'Age': 15}]
list_2 = [{'Product': 'Car', 'Id': 1} , {'Product': 'TV' , 'Id': 2}]
l1 = [l.items() for l in list_1]
l2 = [l.items() for l in list_2]
print [dict(l[0] + l[1]) for l in itertools.product(l1, l2)]

输出结果为:

  

[{'年龄':25,' Id':1,'姓名':' John','产品& #39;:' Car'},{'年龄':25,   ' Id':2,'姓名':' John','产品':' TV'},{& #39;年龄':15,' Id':1,   '姓名':' Mary','产品':' Car'},{'年龄':15,& #39; Id':2,'姓名':   ' Mary',' Product':' TV'}]

如果您的内存效率不足,请尝试:

for l in itertools.product(l1.iteritems() for l1 in list_1,
                           l2.iteritems() for l2 in list_2):
    # work with one product at a time

答案 2 :(得分:0)

对于Python 3:

import itertools

list_1 = [{'Name': 'John' , 'Age': 25} , {'Name': 'Mary' , 'Age': 15}]
list_2 = [{'Product': 'Car', 'Id': 1} , {'Product': 'TV' , 'Id': 2}]
print ([{**l[0], **l[1]} for l in itertools.product(list_1, list_2)])