假设我们有一个二部图,其中的节点表示为列表。例如,假设二部图的节点为l1 = [1,2,3,4,5]
,而l2 = [6,7,8,9,10]
是两个分区中的节点。边为[[1,8,'a'],[4,9,'b' ]]表示为列表1
如果我们以某种方式合并了二部图的节点,并且现在在1中用[[1,2,3], [4, 5]]
和[[6,7] , [8, 9, 10]]
表示,那么在这个新图中,我们将在它们之间具有边如果原始图中的任何一对之间存在边,则进行分组。例如,在上文中,组a
和[1,2,3]
之间将有一个[8,9,10]
边缘,因为最初在1和8之间有一个边缘,如图{{3} }。如何在Python中的新图形中找到边缘,什么是合适的数据结构表示形式,以及如何从原始图形中找到生成的边缘?
我为此使用了列表,但是问题是要找到这些边缘,我必须遍历新图中的所有节点以检查是否应该有边缘。有没有更有效的方法可以做到这一点?
我尝试过的代码:
l1 = [1,2,3,4,5]
l2 = [6,7,8,9,10]
l3 = [[1,2,3], [4, 5]]
l4 = [[6,7] , [8, 9, 10]]
edges = [[1,8, 'a'], [4,9,'b']]
for e in edges:
for l in l3:
for k in l4:
if e[0] in l and e[1] in k:
print(e[0], e[1], e[2])
答案 0 :(得分:2)
首先获取包含特定值的组的索引。
def idx_group_in_list(value, list_) -> int:
"""e.g. value=2, list_=[[1,2],[3,4]] -> 0
because the value 2 is in the first (idx=0) inner list"""
for idx, l in enumerate(list_):
if value in l:
return idx
return -1
在下面,我正在使用基于字典的解决方案。这样可以更轻松地检查边缘是否已经存在。
l3 = [[1, 2, 3], [4, 5]]
l4 = [[6, 7], [8, 9, 10]]
edges = [[1, 8, 'a'], [4, 9, 'b']]
new_edges = {}
for e in edges:
# left
l_idx = idx_group_in_list(e[0], l3)
r_idx = idx_group_in_list(e[1], l4)
if (l_idx, r_idx) in new_edges:
pass # two edges are squeezed. Maybe add some special stuff here
new_edges[(l_idx, r_idx)] = e[2]
print(new_edges)
expected_output = {(0, 1): 'a', (1, 1): 'b'}
print(expected_output == new_edges)
我做了一些非常简单的性能测试。大多数代码保持不变,只是更改了方式,即生成了列表。
num_nodes_per_side = 1000
left = [[i] for i in range(num_nodes_per_side)]
right = [[i] for i in range(num_nodes_per_side, num_nodes_per_side*2)]
edges = [[i, j, 'a'] for i, j in zip(range(num_nodes_per_side), range(num_nodes_per_side, num_nodes_per_side*2))]
# result for num_nodes_per_side = 3
>>> left
[[0], [1], [2]]
>>> right
[[3], [4], [5]]
>>> edges
[[0, 3, 'a'], [1, 4, 'a'], [2, 5, 'a']]
这意味着您从左组的每个边缘到右组的每个边缘。
以下是基于num_nodes_per_side
的时间结果。
答案 1 :(得分:1)
要获得更好的性能,可以使用dict
到inverted index(确保节点ID是唯一的)。这样可以将搜索时间的复杂度从O(n)提高到O(1),但是您需要花费一定的成本来重建数据结构。这是示例代码:
d3 = {node : idx for idx, l in enumerate(l3) for node in l}
d4 = {node : idx for idx, l in enumerate(l4) for node in l}
for node1, node2, name in edges:
if node1 in d3 and node2 in d4 or node2 in d3 and node1 in d4:
print(node1, node2, name)
输出:
1 8 a
4 9 b
如果要像@Uli Sotschok一样检查重复的边缘,这很简单:
new_edges = {}
for node1, node2, name in edges:
if node1 in d3 and node2 in d4:
l_idx = d3[node1]
r_idx = d4[node2]
if (l_idx, r_idx) not in new_edges:
new_edges[(l_idx, r_idx)] = name
print(new_edges)
expected_output = {(0, 1): 'a', (1, 1): 'b'}
print(expected_output == new_edges)
输出:
{(0, 1): 'a', (1, 1): 'b'}
True