简体   繁体   English

合并python集字典

[英]merge python dictionary of sets

I have a graph with 2 kinds of nodes- 'Letter nodes' (L) and 'Number nodes' (N). 我有一个带有2种节点的图-“字母节点”(L)和“数字节点”(N)。 I have 2 dictionaries, one shows edges from L to N and the other shows edges from N to L. 我有2个字典,一个显示从L到N的边缘,另一个显示从N到L的边缘。

 A = {0:(b,), 1:(c,), 2:(c,), 3:(c,)}
 B = {a:(3,), b:(0,), c:(1,2,3)} 

A key,value pair c:(1,2,3) means there are edges from c to 1,2,3 (3 edges) 键值对c:(1,2,3)表示存在从c1,2,3边(3个边)

I want to merge these to one dictionary C so that the result is a new dictionary: 我想将它们合并到一个字典C以便结果是一个新字典:

C = {(0,): (b,), (1, 2, 3): (a, c)}

or 要么

C = {(b,):(0,), (a, c):(1, 2, 3)}

In the resulting dictionary I want the letter nodes and numerical nodes to be on separate sides of keys and values. 在生成的字典中,我希望字母节点和数字节点位于键和值的不同侧。 I don't care which is the key or value just need them separated. 我不在乎哪个是键或值,只需要将它们分开即可。 How can I go about solving this efficiently? 我该如何有效地解决这个问题?

CLARIFICATION: this of a graph with 2 types of nodes - number nodes, and letter nodes. 澄清:这是一种具有2种类型的节点的图-数字节点和字母节点。 the dictionary C says from letter nodes (a,c) you can reach the number nodes (1,2,3) ie a->3->c->1, a->3->c->2 thus you can get to 1,2,3 from a. 字典C说从字母节点(a,c)可以到达数字节点(1,2,3),即a-> 3-> c-> 1,a-> 3-> c-> 2因此您可以从a到1,2,3 EVEN THOUGH THERE IS NO DIRECT EDGE FROM a to 2 or a to 1. 即使从a到2或a到1都没有直接边缘。

According to your statement, I guess you are trying to find a graph algorithms. 根据您的陈述,我想您正在尝试找到一种图形算法。

import itertools
def update_dict(A, result): #update vaules to the same set
    for k in A:
        result[k] = result.get(k, {k}).union(set(A[k]))
        tmp = None
        for i in result[k]:
            tmp = result.get(k, {k}).union(result.get(i, {i}))
        result[k] = tmp
        for i in result[k]:
            result[i] = result.get(i, {i}).union(result.get(k, {k}))

A = {0:('b',), 1:('c',), 2:('c',), 3:('c',)}
B = {'a':(3,), 'b':(0,), 'c':(1,2,3)}
result = dict()
update_dict(A, result)
update_dict(B, result)
update_dict(A, result) #update to fix bugs
update_dict(B, result)

k = sorted([sorted(list(v)) for v in result.values()]) 
k = list( k for k, _ in itertools.groupby(k))  #sort and remove dumplicated set

final_result = dict()
for v in k: #merge the result as expected
    final_result.update({tuple([i for i in v if isinstance(i, int)]):tuple([i for i in v if not isinstance(i, int)])})
print final_result

#output
{(0,): ('b',), (1, 2, 3): ('a', 'c')}

So I'm not sure if this is the most efficient way of doing this at this point, but it works: 因此,我目前尚不确定这是否是最有效的方法,但它的工作原理是:

 A = {0:('b',), 1:('c',), 2:('c',), 3:('c',)}
 B = {'a':(3,), 'b':(0,), 'c':(1,2,3)} 

# Put B in the same form as A

B_inv = {}
for k, v in B.items():
    for i in v:
        if B_inv.get(i) is not None:
            B_inv[i] = B_inv[i].union(k)
        else:
            B_inv[i] = set(k)

B_inv = {k: tuple(v) for k, v in B_inv.items()}
AB = set(B_inv.items() + A.items())  # get AB as merged

This gets you the merged dictionaries. 这使您合并了词典。 From here: 从这里:

new_dict = {}
for a in AB:
    for i in a[1]:
        if new_dict.get(i) is not None:
            new_dict[i] = new_dict[i].union([a[0]])
        else:
            new_dict[i] = set([a[0]])

# put in tuple form
new_dict = {tuple(k): tuple(v) for k,v in new_dict.items()}

This gives me: 这给了我:

{('a',): (3,), ('b',): (0,), ('c',): (1, 2, 3)}

Basically, I'm relying on the mutability of sets and their built-in functionality of eliminating duplicates to try to keep the number of loops through each dictionary to a minimum. 基本上,我依靠集合的可变性及其消除重复项的内置功能,以尝试使每个字典中的循环数保持最小。 Unless I missed something, this should be in linear time. 除非我错过任何事情,否则应该是线性时间。

From here, I need to do comparison, and relying on sets again to prevent me from needing to do a worst-case pairwise comparison of every single element. 从这里开始,我需要进行比较,并再次依赖于集合,以防止我需要对每个单个元素进行最坏情况的成对比较。

merge_list = []

for k, v in new_dict.items():
    matched = False
    nodeset = set([k[0]]).union(v)
    for i in range(len(merge_list)):
        if len(nodeset.intersection(merge_list[i])) != 0:
            merge_list[i] = merge_list[i].union(nodeset)
            matched = True

    # did not find shared edges
    if not matched:
        merge_list.append(nodeset)

Finally, turn it into the form with a single "layer" and tuples. 最后,将其转换为具有单个“层”和元组的形式。

C = {}

for item in merge_list:
    temp_key = []
    temp_val = []

    for i in item:
        if str(i).isalpha():
            temp_key.append(i)
        else:
            temp_val.append(i)

    C[tuple(temp_key)] = tuple(temp_val)

C gives me {('a', 'c'): (1, 3, 2), ('b',): (0,)} . C给我{('a', 'c'): (1, 3, 2), ('b',): (0,)}

try this: 尝试这个:

c = a.copy()
c.update(b)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM