两个字典python的笛卡尔积

时间:2013-11-13 19:39:42

标签: 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', '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

5 个答案:

答案 0 :(得分:5)

最佳猜测,基于@ abarnert的解释(并假设当前输出中的healthyinsane值是错误的,因为它们只有四个成员):

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')

答案 1 :(得分:4)

试试这个:它结合了两个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)}  

答案 2 :(得分:3)

我前一段时间遇到过这个问题。我现在有一个名为'looper'的pip包,它使用一些字典魔法和其他我发现有用的东西扩展了itertools。

https://pypi.python.org/pypi/looper

你想要的东西似乎不是两个词典的完整笛卡尔积,长度为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'}

答案 3 :(得分:1)

  

我需要的是第一个字典重复第一个值第二个字典中值的次数

好的,所以你想用第二个字典中值的zip来产生第一个字典中的每个值,反之亦然。

要做到这一点,你必须解压缩两个字典的值,产生结果,解压缩,用相应的原始字典中的键将生成的2元组的每一半压缩,压平两个产生的密钥的迭代-value成对,并从中创建一个字典。 (您可以将这些值展平并将其压缩到两个dicts中的扁平键,但我不确定这是否保证了正确的顺序......)

这听起来像是一团糟,但这就是你所要求的。

答案 4 :(得分:0)

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

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