Python 两个字典的笛卡尔积

Python 两个字典的笛卡尔积,python,python-3.x,dictionary,itertools,cartesian-product,Python,Python 3.x,Dictionary,Itertools,Cartesian Product,好的,我有两本字典 dictionary_1 = {'status': ['online', 'Away', 'Offline'], 'Absent':['yes', 'no', 'half day']} dictionary_2 = {'healthy': ['yes', 'no'], 'insane': ['yes', 'no'] 现在我需要将它们结合起来,这样我就可以得到一本新的字典: {'status': ['online

好的,我有两本字典

dictionary_1 = {'status': ['online', 'Away', 'Offline'],
                'Absent':['yes', 'no', 'half day']}
dictionary_2 = {'healthy': ['yes', 'no'],
                'insane': ['yes', 'no']
现在我需要将它们结合起来,这样我就可以得到一本新的字典:

{'status': ['online', 'online', 'away', 'away', 'Offline', 'Offline'],
 'Absent': ['yes', 'yes', 'no', 'no', 'half day', 'half day'],
 'healthy': ['yes', 'no', 'yes', 'no', 'yes', 'no'],
 'insane': ['yes', 'no', 'yes', 'no', 'yes', 'no']
}
这是一个非常晚的更新,但如果有人感兴趣,我找到了一种不用itertools的方法

def cartesian_product(dict1, dict2):
    cartesian_dict = {}
    dict1_length = len(list(dict1.values())[0])
    dict2_length = len(list(dict2.values())[0])
    h = []
    for key in dict1:
        for value in dict1[key]:
            if not key in cartesian_dict:
                cartesian_dict[key] = []
                cartesian_dict[key].extend([value]*dict2_length)
            else:   
                cartesian_dict[key].extend([value]*dict2_length)
    for key in dict2:
        cartesian_dict[key] = dict2[key]*dict1_length
    return cartesian_dict

将词典放入数组,然后执行以下操作:

dictionaries[dict_1,dict_2]

product = {}
arr = []
for d in dictionaries:
    for k in dictionaries[d]:
        arr.append(d.get(k))
        product[k] = None
for k in product:
    product[k] = arr

我需要的是,第一个字典重复第一个值的数量乘以第二个字典中的值

好的,那么您希望将第一个字典中的每个值与第二个字典中的值的zip进行乘积,反之亦然

要做到这一点,您必须解压两个字典的值,生成结果,解压结果,用对应原始字典中的键将结果2元组的每一半解压,将结果的两个键-值对的iterables展平为一个,并用它制作一个字典。您可以将值展平并将其压缩到两个dict中的展平键,但我不确定这是否保证了正确的顺序


这听起来很混乱,但这正是你想要的。

根据@abarnert的解释,并假设当前输出中的健康值和疯狂值是错误的,因为它们只有四个成员:

d1 = {'status': ['online', 'Away', 'Offline'] ,'absent':['yes', 'no', 'half day']}
d2 = {'healthy': ['yes', 'no'], 'insane': ['yes', 'no']}
d1_columns = zip(*d1.values())
d2_columns = zip(*d2.values())
col_groups = [c1+c2 for c1, c2 in itertools.product(d1_columns, d2_columns)]
rows = zip(*col_groups)
combined_keys = list(d1) + list(d2)
d_combined = dict(zip(combined_keys, rows))
产生

>>> pprint.pprint(d_combined)
{'absent': ('yes', 'yes', 'no', 'no', 'half day', 'half day'),
 'healthy': ('yes', 'no', 'yes', 'no', 'yes', 'no'),
 'insane': ('yes', 'no', 'yes', 'no', 'yes', 'no'),
 'status': ('online', 'online', 'Away', 'Away', 'Offline', 'Offline')}
或者,按照你的命令

>>> order = ["status", "absent", "healthy", "insane"]
>>> for k in order:
    print k, d_combined[k]
...     
status ('online', 'online', 'Away', 'Away', 'Offline', 'Offline')
absent ('yes', 'yes', 'no', 'no', 'half day', 'half day')
healthy ('yes', 'no', 'yes', 'no', 'yes', 'no')
insane ('yes', 'no', 'yes', 'no', 'yes', 'no')

试试这个:它将两个dict值组合起来,生成产品,然后将它们重新分离,变成dict

import itertools

dictionary_1 = {'status': ['online', 'Away', 'Offline'],
                'Absent':['yes', 'no', 'half day']}
dictionary_2 = {'healthy': ['yes', 'no', 'recovering'],
                'insane': ['yes', 'no', 'partially' ]}

keys = dictionary_1.keys() + dictionary_2.keys()

first_values = zip(*dictionary_1.values())
# [('online','yes'), ('Away','no'),('Offline','half day')]

second_values = zip(*dictionary_2.values())

# this product will replicate the first_values 
# as many times as second_values exists
values_list = [i1+i2 for(i1,i2) in itertools.product(first_values,second_values)]

#re-separate the value lists for dict.
values = zip(*values_list)

new_dict = {key:list(values[i]) for i,key in enumerate(keys)}  

不久前,我在制作测试用例时遇到了这个问题。我在pip上有一个名为“looper”的包,它通过一些字典魔法和其他我发现有用的东西扩展了itertools

您想要的似乎不是两个字典的完整笛卡尔积,这两个字典将有36个条目长,每个键组合为d1[k1]*d1[k2]*d2[k1]*d2[k2]

相反,您似乎希望d1[k1,k2]*d2[k1,k2],为每个键均匀地迭代n。这被称为zip函数,dict_zip为字典实现了这一功能

from pprint import pprint
from looper import iterutil

dict_1 = {'status':  ['online', 'Away', 'Offline'],
          'Absent':  ['yes', 'no', 'half day']}
dict_2 = {'healthy': ['yes', 'no'],
          'insane':  ['yes', 'no']}

# the first thing to do is to zip the dictionaries up. This produces a dictionary for each value of n in d[k][n]
zipped_dict_1 = iterutil.dict_zip(**dict_1)
# {'Absent': 'yes', 'status': 'online'}
# {'Absent': 'no', 'status': 'Away'}
# {'Absent': 'half day', 'status': 'Offline'}
zipped_dict_2 = iterutil.dict_zip(**dict_2)
# {'healthy': 'yes', 'insane': 'yes'}
# {'healthy': 'no', 'insane': 'no'}


# Now the output is a list of flattened dictionaries, take the Cartesian product of them.
product_dict = iterutil.product(zipped_dict_1,zipped_dict_2) 
# ({'Absent': 'yes', 'status': 'online'}, {'healthy': 'yes', 'insane': 'yes'})
# ({'Absent': 'yes', 'status': 'online'}, {'healthy': 'no', 'insane': 'no'})
# ({'Absent': 'no', 'status': 'Away'}, {'healthy': 'yes', 'insane': 'yes'})
# ({'Absent': 'no', 'status': 'Away'}, {'healthy': 'no', 'insane': 'no'})
# ({'Absent': 'half day', 'status': 'Offline'}, {'healthy': 'yes', 'insane': 'yes'})
# ({'Absent': 'half day', 'status': 'Offline'}, {'healthy': 'no', 'insane': 'no'})

# The product function produces tuples which must be combined in to a final dictionary.
# Merge the dictionaries using imap
merged_dict =  iterutil.imap(lambda x: dict(x[0].items()+x[1].items()),product_dict)

for d in merged_dict:
    pprint(d)
输出

{'Absent': 'yes', 'healthy': 'yes', 'insane': 'yes', 'status': 'online'}
{'Absent': 'yes', 'healthy': 'no', 'insane': 'no', 'status': 'online'}
{'Absent': 'no', 'healthy': 'yes', 'insane': 'yes', 'status': 'Away'}
{'Absent': 'no', 'healthy': 'no', 'insane': 'no', 'status': 'Away'}
{'Absent': 'half day', 'healthy': 'yes', 'insane': 'yes', 'status': 'Offline'}
{'Absent': 'half day', 'healthy': 'no', 'insane': 'no', 'status': 'Offline'}

你的前两个是压缩的li,你的后两个是连接3个li副本。你想要哪一个?你怎么会得到三份“在线”的?你是否试图为ziphealthy的每个成员获取一份状态副本,精神错乱,为ziphealthy的每个成员获取一份缺席状态副本,为zipstatus的每个成员获取一份健康状态副本,为zipstatus的每个成员获取一份缺席状态副本?请解释你的笛卡尔积,您的预期输出不太明显。我需要的是第一个字典重复第一个值第二个字典中的值的次数。。。每个字典都有一定数量的键,每个键都有相同数量的值。因此,我需要第一个字典中的键的值与第二个字典中的键的值重复相同的次数。您的编辑使这一点更加混乱。“部分”和“恢复”到哪里去了?它们是如何神奇地在输出中结束的?很好的Python翻译。Python和英语一样混乱,但这不是你的错……如果d1.viewkeys和d2.viewkeys不是空的,也就是说,如果有公共键,那么预期结果是什么还不清楚。@J.F.Sebastian:好的。以上只有在它们不相交的情况下才有意义。像一个符咒一样工作。。。谢谢你,实际上我需要的是一个列表,而不是一个元组。我想有一种明显的方法可以做到这一点,即使在根本不明显的情况下^是的,我们似乎到达了同一个地方!这很有趣,除了dict结构外,几乎每行都是一样的。不许复制,我发誓