如何根据共享项目有效地对配对?

时间:2019-03-19 01:36:34

标签: python networking grouping

为简化起见,我有一个成对(元组)列表:

L = [("A","B"), ("B","C"), ("C","D"), ("E","F"), ("G","H"), ("H","I"), ("G","I"), ("G","J")]

我要使用python有效地将此列表拆分为:

L1 = [("A","B"), ("B","C"), ("C","D")]
L2 = [("E","F")]
L3 = [("G","H"), ("G","I"), ("G","J"), ("H","I")]

如何有效地将列表分成几对,对于该组中的对,必须总是至少有一对与其他项共享一个项目?如答案之一所述,这是实际上是网络问题。目标是有效地将网络分成断开(隔离)的网络部分。

可以更改类型列表,元组(集合)以实现更高的效率。

5 个答案:

答案 0 :(得分:4)

这更像是网络问题,因此我们使用networks

import networkx as nx
G=nx.from_edgelist(L)

l=list(nx.connected_components(G))
# after that we create the map dict , for get the unique id for each nodes
mapdict={z:x for x, y in enumerate(l) for z in y }
# then append the id back to original data for groupby 
newlist=[ x+(mapdict[x[0]],)for  x in L]
import itertools
#using groupby make the same id into one sublist
newlist=sorted(newlist,key=lambda x : x[2])
yourlist=[list(y) for x , y in itertools.groupby(newlist,key=lambda x : x[2])]
yourlist
[[('A', 'B', 0), ('B', 'C', 0), ('C', 'D', 0)], [('E', 'F', 1)], [('G', 'H', 2), ('H', 'I', 2), ('G', 'I', 2), ('G', 'J', 2)]]

匹配您的输出

L1,L2,L3=[[y[:2]for y in x] for x in yourlist]
L1
[('A', 'B'), ('B', 'C'), ('C', 'D')]
L2
[('E', 'F')]
L3
[('G', 'H'), ('H', 'I'), ('G', 'I'), ('G', 'J')]

答案 1 :(得分:1)

  • 将组列表初始化为空
  • (a, b)是下一对
  • 使用ab收集包含任何元素的所有组
  • 全部删除,加入,添加(a, b),然后作为新群组插入
  • 重复直到完成

就像这样:

import itertools, functools

def partition(pred, iterable):
    t1, t2 = itertools.tee(iterable)
    return itertools.filterfalse(pred, t1), filter(pred, t2)

groups = []
for a, b in L:
    unrelated, related = partition(lambda group: any(aa == a or bb == b or aa == b or bb == a for aa, bb in group), groups)
    groups = [*unrelated, sum(related, [(a, b)])]

答案 2 :(得分:1)

您可以使用以下代码:

l = [("A","B"), ("B","C"), ("C","D"), ("E","F"), ("G","H"), ("H","I"), ("G","I"), ("G","J")]

result = []
if len(l) > 1:
  tmp = [l[0]]
  for i in range(1,len(l)):
    if l[i][0] == l[i-1][1] or l[i][1] == l[i-1][0] or l[i][1] == l[i-1][1] or l[i][0] == l[i-1][0]:
      tmp.append(l[i])
    else:
      result.append(tmp)
      tmp = [l[i]]
  result.append(tmp)
else:
  result = l

for elem in result:
  print(elem)

输出

[('A', 'B'), ('B', 'C'), ('C', 'D')]
[('E', 'F')]
[('G', 'H'), ('H', 'I'), ('G', 'I'), ('G', 'J')]

注意:此代码基于对初始数组进行排序的假设。如果不是这种情况,它将无法正常工作,因为它只会遍历整个列表来创建组(复杂性O(n))。

说明:

  • result将存储您的组
  • if len(l) > 1:,如果列表中只有一个元素或列表为空,则无需进行任何处理即可。
  • 您将在列表的每个元素上进行一次遍历,并比较位置i的元组和位置i-1的元组之间的4种可能的相等性。
  • tmp用于构造您的组,只要满足条件,您就可以在tmp中添加元组
  • 不遵守条件时,添加tmp(已创建到结果中的当前组,使用当前元组重新启动tmp)。

答案 3 :(得分:1)

一种高效且Python化的方法是将元组列表转换为一组冻结集作为候选池,并在while循环中将其创建为组并使用嵌套的while循环以通过添加第一个候选集并随后与与该组相交的其他候选集执行集并集来继续扩展组,直到不再有相交的候选集为止,这时返回外循环以形成一个新组: / p>

pool = set(map(frozenset, L))
groups = []
while pool:
    group = set()
    groups.append([])
    while True:
        for candidate in pool:
            if not group or group & candidate:
                group |= candidate
                groups[-1].append(tuple(candidate))
                pool.remove(candidate)
                break
        else:
            break

鉴于您的示例输入,groups将变为:

[[('A', 'B'), ('C', 'B'), ('C', 'D')],
 [('G', 'H'), ('H', 'I'), ('G', 'J'), ('G', 'I')],
 [('E', 'F')]]

请记住,Python中的集合是无序的,这就是为什么上述输出的顺序与您期望的输出不匹配,但出于您的目的顺序不重要的原因。

答案 4 :(得分:0)

您可以使用while循环并从L的第一个成员开始迭代(在内部使用for循环)。检查是否有任何成员(两个成员都共享)整个列表。然后将其附加到列表L1并从原始列表L中弹出该成员。然后while循环将再次运行(直到列表L为非空)。并且for循环将对列表中的每个元素运行,以追加到新列表L2。你可以试试看(我将提供没有帮助的代码)