基于共享值的群集列表

时间:2018-05-25 23:13:47

标签: python algorithm

我有一个列表列表,其中每个子列表包含一些整数:

o = [[1,2],[3,4],[2,3],[5,4]]

我想创建一个新的列表列表,其中o中共享公共成员的任何两个子列表将被合并。这个合并过程应该继续,直到没有两个子列表共享一个共同的元素。鉴于o,我们会将[1,2][2,3]合并,因为它们共享2,然后我们将该组与[3,4]合并,因为[1,2,3]和{ {1}}都包含3,依此类推。

群集[3,4]的预期输出为o

我有预感,这项任务的方法远远优于我目前的方法(见下文)。任何其他人可以提供的最有效(时间,空间)方式的建议将非常感激。

[[1,2,3,4,5]]

2 个答案:

答案 0 :(得分:2)

from collections import deque

o = [[1,2],[3,4],[2,3],[5,4], [10, 11, 12], [13, 15], [4,6], [6, 8], [23,25]]

o = sorted(o, key=lambda x:min(x))
queue = deque(o)

grouped = []
while len(queue) >= 2:
    l1 = queue.popleft()
    l2 = queue.popleft()
    s1 = set(l1)
    s2 = set(l2)

    if s1 & s2:
        queue.appendleft(s1 | s2)
    else:
        grouped.append(s1)
        queue.appendleft(s2)
#         print(set(l1).union(set(l2)))
if queue:
    grouped.append(queue.pop())

print(grouped)

<强>输出

[set([1, 2, 3, 4, 5, 6, 8]), set([10, 11, 12]), set([13, 15]), set([25, 23])]

答案 1 :(得分:0)

您可以使用递归:

def cluster(d, current = []):
  options = [i for i in d if any(c in current for c in i)]
  _flattened = [i for b in options for i in b]
  d = list(filter(lambda x:x not in options, d))
  if not options or not d:
    yield current+_flattened
  if d and not options:
    yield from cluster(d[1:], d[0])
  elif d:
    yield from cluster(d, current+_flattened)

for a, *b in [[[1,2],[6,4],[2,3],[5,4]], [[1,2],[3,4],[2,3],[5,4]], [[1,2],[3,4],[2,3],[5,4], [10, 11, 12], [13, 15], [4,6], [6, 8], [23,25]]]:
  print([list(set(i)) for i in cluster(b, a)])

输出:

[[1, 2, 3], [4, 5, 6]]
[[1, 2, 3, 4, 5]]
[[1, 2, 3, 4, 5, 6, 8], [10, 11, 12], [13, 15], [25, 23]]
相关问题