python - 用所有相交条目的并集更新所有列表条目的最快方法

标签 python arrays algorithm performance intersection

我正在寻找一种快速方法来遍历集合列表,并通过找到它与列表中至少共享一个元素的任何其他元素的并集来扩展每个集合。
例如,假设我有四行数据,其中每一行对应一组唯一的元素

0, 5, 101
8, 9, 19, 21
78, 79
5, 7, 63, 64
第一行和最后一行有相交元素 5,所以在执行我的操作后我想要联合
0, 5, 7, 63, 64, 101
8, 9, 19, 21
78, 79
0, 5, 7, 63, 64, 101
现在,我几乎可以用两个循环来做到这一点:
def consolidate_list(arr):
    """
    arr (list) : A list of lists, where the inner lists correspond to sets of unique integers
    """
    arr_out = list()
    for item1 in arr:
        item_additional = list() # a list containing all overlapping elements
        for item2 in arr:
            if len(np.intersect1d(item1, item2)) > 0:
                item_additional.append(np.copy(item2))
        out_val = np.unique(np.hstack([np.copy(item1)] + item_additional)) # find union of all lists

        arr_out.append(out_val)
        
return arr_out
这种方法的问题在于它需要运行多次,直到输出停止变化。由于输入可能是锯齿状的(即,每组的元素数量不同),我看不到矢量化此函数的方法。

最佳答案

这个问题是关于创建disjoint sets所以我会使用 union-find 方法。
现在 Python 并不是特别出名,但为了展示算法,这里是一个 DisjointSet 的实现。没有库的类:

class DisjointSet:
    class Element:
        def __init__(self):
            self.parent = self
            self.rank = 0


    def __init__(self):
        self.elements = {}

    def find(self, key):
        el = self.elements.get(key, None)
        if not el:
            el = self.Element()
            self.elements[key] = el
        else: # Path splitting algorithm
            while el.parent != el:
                el, el.parent = el.parent, el.parent.parent
        return el

    def union(self, key=None, *otherkeys):
        if key is not None:
            root = self.find(key)
            for otherkey in otherkeys:
                el = self.find(otherkey)
                if el != root:
                    # Union by rank
                    if root.rank < el.rank:
                        root, el = el, root
                    el.parent = root
                    if root.rank == el.rank:
                        root.rank += 1

    def groups(self):
        result = { el: [] for el in self.elements.values() 
                          if el.parent == el }
        for key in self.elements:
            result[self.find(key)].append(key)
        return result
以下是您如何将其用于此特定问题:
def solve(lists):
    disjoint = DisjointSet()
    for lst in lists:
        disjoint.union(*lst)
            
    groups = disjoint.groups()
    return [lst and groups[disjoint.find(lst[0])] for lst in lists]
示例调用:
data = [
    [0, 5, 101],
    [8, 9, 19, 21],
    [],
    [78, 79],
    [5, 7, 63, 64]
]
result = solve(data)
结果将是:
[[0, 5, 101, 7, 63, 64], [8, 9, 19, 21], [], [78, 79], [0, 5, 101, 7, 63, 64]]
请注意,我在输入列表中添加了一个空列表,以便说明此边界情况保持不变。
注意:有一些库提供联合查找/不相交集功能,每个库的 API 略有不同,但我认为使用其中之一可以提供更好的性能。

关于python - 用所有相交条目的并集更新所有列表条目的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69062015/

相关文章:

python - 访问 statsmodels 中的各个参数

arrays - 查找数组 A 的哪些元素在数组 B 中的有效方法

python - 如何确定跨键盘的最佳路线

javascript - 追加新文件

arrays - 计算动态数组的时间复杂度

python - 用于删除排序数组中重复元素的无循环程序

python - 仅当 Pandas 中的值为空/空时才合并

python - seaborn 在 sublime 中的问题

c - 删除后如何重新排列数组元素

java - 如何交换 ArrayList 中两个对象的位置?