查找表示为列表的边

时间:2019-05-04 11:14:31

标签: python list

假设我们有一个二部图,其中的节点表示为列表。例如,假设二部图的节点为l1 = [1,2,3,4,5],而l2 = [6,7,8,9,10]是两个分区中的节点。边为[[1,8,'a'],[4,9,'b' ]]表示为列表1

中给出的列表

figure 2

如果我们以某种方式合并了二部图的节点,并且现在在1中用[[1,2,3], [4, 5]][[6,7] , [8, 9, 10]]表示,那么在这个新图中,我们将在它们之间具有边如果原始图中的任何一对之间存在边,则进行分组。例如,在上文中,组a[1,2,3]之间将有一个[8,9,10]边缘,因为最初在1和8之间有一个边缘,如图{{3} }。如何在Python中的新图形中找到边缘,什么是合适的数据结构表示形式,以及如何从原始图形中找到生成的边缘?

1

我为此使用了列表,但是问题是要找到这些边缘,我必须遍历新图中的所有节点以检查是否应该有边缘。有没有更有效的方法可以做到这一点?

我尝试过的代码:

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

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的时间结果。

  • 10:2.0693999999987778e-05
  • 100:0.0004394410000000404
  • 1000:0.042664883999999986
  • 10000:4.629786907

答案 1 :(得分:1)

要获得更好的性能,可以使用dictinverted 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