如何将字典的键与常用值合并到元组中。例如:
A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}
output = {('E2', 'E5'): {'5', '7'}, ('E3', 'E8'): {'4', '8'}}
我的尝试:
A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}
output = {}
seen = []
for k, v in A.items():
if v not in [s[1] for s in seen]: # not seen this value yet
print('NOT SEEN')
print(k, v)
seen.append([k,v])
output[k] = v
else: # already seen it
print('SEEN')
print(k, v)
# determine where we've seen it
where = [x for x in seen if x[1]==v]
output.pop(where[0][0])
output[(where[0][0], k)] = v
print('OUTPUT = ', output)
打印:
OUTPUT = {('E2', 'E5'): {'7', '5'}, ('E3', 'E8'): {'4', '8'}}
答案 0 :(得分:4)
我会在两遍中进行转换:
>>> A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}
# First pass: Create a reverse one-to-many mapping.
# The original set() value gets converted to a hashable frozenset()
# and used as a key. The original scalar string key gets accumulated
# in a list to track the multiple occurrences.
>>> reverse = {}
>>> for key, value in A.items():
reverse.setdefault(frozenset(value), []).append(key)
# Second pass: reverse the keys and values. The list of matching
# values gets converted to a hashable tuple (as specified by the OP)
# and the frozenset() gets restored back to the original set() type.
>>> {tuple(value) : set(key) for key, value in reverse.items()}
{('E2', 'E5'): {'5', '7'}, ('E3', 'E8'): {'8', '4'}}
这给出了OP预期的输出。
注意,输入字典没有保证顺序,也没有原始输入中的任何集合。因此,输出不能保证条款的有序排序。
答案 1 :(得分:2)
import itertools
A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}
def key(x):
# List supports ordering
return sorted(list(x[1]))
def gen():
for (group_key, group) in itertools.groupby(sorted(A.items(), key=key), key=key):
gl = list(group)
yield (tuple(x[0] for x in gl),
gl[0][1] # group_key is a list, but we want original set
)
print(dict(gen()))
如果您已准备好说服自己set-> list->设置转换是安全的,那么您可以制作单行代码而不是生成器:
print(dict((tuple(g[0] for g in group), set(group_key)) for
(group_key, group) in
itertools.groupby(sorted(A.items(), key=key), key=key)))
UPD:那么,到底发生了什么?
首先,我们通过调用.items()
将dict转换为可迭代的元组。
我们想要将具有相同第二个元素(具有索引1或前一个dict值)的迭代项组合在一起。
这正是itertools.groupby
的作用。参数是一个可迭代的键,我们将通过它组合。看来,key=lambda kv: kv[1]
是可行的。不幸的是。我们可以比较集合的相等性,但是文档说可迭代应该是有序的。并且sorted
函数要求密钥与订单相当。无法按列表的顺序比较集。我们可以安全地创建一个包含与set相同元素的列表,但是我们应该对它进行排序(相等的集合可以生成具有不同顺序的列表{5, 7} == {7, 5}
,但是[5, 7] != [7, 5]
)。
现在,在排序和分组之后,我们有以下数据结构:
[
(key_dict_value as list, iterable of (dict_key, dict_value) that has dict_value == key_dict_value),
...
]
现在我们可以迭代这个iterable并创建另一个可迭代的元组。我们采用每个元组的第二个元素(可迭代,索引为1)并将其转换为元组(这是我们未来字典的关键)。我们未来字典的值是原始字典中的值。我们可以从元组的第二个元素的某个元素(此可迭代不能为空,因为groupby
不能生成空组,请参见第一个片段)或从key_dict_value
转换回列表(这是安全的,因为这个列表是从集合中生成的,因此它没有相同的元素,请参阅第二个片段。)
<强> UPD2 强>
在我写作解释时,我发现sorted
对于平等的关键不合适,但对groupby
来说很好,所以这里更简单的解决方案没有定义key
函数和转换列表回到设定:
print(dict((tuple(g[0] for g in group), group_key) for
(group_key, group) in itertools.groupby(sorted(A.items(),
key=lambda x: sorted(list(x[1]))),
key=lambda x: x[1])))
答案 2 :(得分:2)
你可以试试这个:
from collections import defaultdict
A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}
second_new = defaultdict(list)
for a, b in A.items():
second_new[tuple(b)].append(a)
final_dict = {tuple(b):set(a) for a, b in second_new.items()}
输出:
{('E8', 'E3'): {'8', '4'}, ('E5', 'E2'): {'5', '7'}}
答案 3 :(得分:1)
这是我使用理解的方法。只需要两个中间步骤,并且只使用内置数据类型。
# get unique values from original dict
targ_values = set([tuple(v) for v in A.values()])
# build lists of original keys that match the temp_keys
targ_values = {targ_value:[orig_key for orig_key, orig_value in A.items() if tuple(orig_value) == targ_value] for targ_value in targ_values}
# reverse the order of keys & values and convert types to get desired output
output = {tuple(v):set(k) for k, v in targ_values.items()}