我有一个大数组命名为whoHasMe如下:
whoHasMe: [[0], [1], [0, 2, 3], [1, 2, 3, 4, 5], [4], [5], [6, 7, 8], [7], [6, 8]]
我们可以注意到,这些
whoHasMe[0]与whoHasMe[2]有关系
whoHasMe[1]与whoHasMe[3]有关系
whoHasMe[2]与whoHasMe[3]有关系
whoHasMe[4]与whoHasMe[3]有关系
whoHasMe[5]与whoHasMe关系[3]
whoHasMe[6]与whoHasMe[7]有关系
whoHasMe[8]有关系whoHasMe [7]
如何将它分组成另一个新的大数组?
finalBigArray = [[0,1,2,3,4,5], [6,7,8]]
注意:whoHasMe数组的值可能会改变。寻求帮助如何找到它的关系和建立一个最终的大数组。
谢谢你,祝你有美好的一天。
我能想到的方法是使用disjoint set。这是一个简单的实现:
class DisjointSet:
def __init__(self, n):
self.root = list(range(n))
def __getitem__(self, k): # find root
return k if self.root[k] == k else self[self.root[k]]
def union(self, a, b):
x, y = self[a], self[b]
if x != y:
self.root[y] = x
首先,将给定列表中的每个列表转换为一个集合:
lst = [[0], [1], [0, 2, 3], [1, 2, 3, 4, 5], [4], [5], [6, 7, 8], [7], [6, 8]]
lst = list(map(set, lst))
然后判断每对组合之间是否存在关系。如果是,将它们的索引联合:
length = len(lst)
ds = DisjointSet(length)
for i in range(length):
for j in range(i + 1, length):
if lst[i] & lst[j]:
ds.union(i, j)
上一步的两层环可以通过
简化itertools.combinations
:from itertools import combinations for (i, s1), (j, s2) in combinations(enumerate(lst), 2): if s1 & s2: ds.union(i, j)
在defaultdict
的帮助下,我们得到了同一集合中的并集:
from collections import defaultdict
d = defaultdict(set)
for i in range(length):
d[ds[i]] |= lst[i]
最后,将字典值转换为列表:
print(list(map(sorted, d.values())))
输出:
[[0, 1, 2, 3, 4, 5], [6, 7, 8]]
更新:
我稍微修改了不相交集,将递归转换为循环,并通过__getitem__
方法和__len__
方法使其支持迭代。最后的代码如下:
from collections import defaultdict
from itertools import combinations
class DisjointSet:
def __init__(self, n):
self.root = [None] * n
def __getitem__(self, k):
root = self.root
while (r := root[k]) is not None:
k = r
return k
def __len__(self):
return len(self.root)
def union(self, a, b):
x, y = self[a], self[b]
if x != y:
self.root[y] = x
def my_merge(lists):
lists = list(map(set, lists))
ds = DisjointSet(len(lists))
for (i, s1), (j, s2) in combinations(enumerate(lists), 2):
if s1 & s2:
ds.union(i, j)
d = defaultdict(set)
for r, s in zip(ds, lists):
d[r] |= s
return list(map(sorted, d.values()))
一些测试:
import random
for _ in range(3):
lst = [sorted(random.randint(0, 50) for _ in range(random.randint(1, 6))) for _ in range(5)]
print(f'lists: {lst}')
print(f'result: {my_merge(lst)}')
输出:
lists: [[21, 26, 42, 44, 47], [4, 27, 40, 49], [5, 20, 39, 50], [14, 40, 47], [6]]
result: [[4, 14, 21, 26, 27, 40, 42, 44, 47, 49], [5, 20, 39, 50], [6]]
lists: [[14, 26], [22], [4], [18, 22, 33, 37], [4, 5, 13, 19, 38, 46]]
result: [[14, 26], [18, 22, 33, 37], [4, 5, 13, 19, 38, 46]]
lists: [[9, 9, 21, 31, 41], [7, 9, 28, 35, 43], [13, 23, 37, 42, 45], [4, 14, 21, 25], [0, 12, 14, 39, 50]]
result: [[0, 4, 7, 9, 12, 14, 21, 25, 28, 31, 35, 39, 41, 43, 50], [13, 23, 37, 42, 45]]
之前的答案有问题,以下是新的更正版本,如有问题请纠正我指定一个变量项作为嵌套列表的第一项,嵌套列表遍历,将他们组合分配给第一个项目如果有一个列表,可以结合,然后删除符合条件的项目,直接进入下一个循环,这将确保每个循环可以合并一次,如果没有找到有效的组合这个循环结束时,项目是独立的,如果没有找到有效组合的循环,然后项目是独立的,可以添加到结果列表中并依次重复(这种方法对于大量数据可能不有效,寻找其他有效的解决方案)
def merge(intervals):
res = []
while len(intervals):
is_new = True
item = intervals[0]
for index in range(1, len(intervals)):
if set(item) & set(intervals[index]):
intervals[0] = list(set(item + intervals[index]))
intervals.pop(index)
is_new = False
break
if is_new:
res.append(intervals[0])
intervals = intervals[1:]
return res
print(merge([[0], [1], [0, 2, 3], [1, 2, 3, 4, 10], [4], [5], [6, 7, 8], [7], [6, 3], [9, 10]]))
print(merge([[0], [1], [0, 2, 3], [1, 2, 3, 4, 5], [4], [5], [6, 7, 8], [7], [6, 8]]))
# Output
# [[0, 1, 2, 3, 4, 6, 7, 8, 9, 10], [5]]
# [[0, 1, 2, 3, 4, 5], [8, 6, 7]]