传递闭包 Python 元组

13 投票
7 回答
9651 浏览
提问于 2025-04-17 09:14

有没有人知道Python里有没有内置的方法可以计算元组的传递闭包?

我有一些元组,比如(1,2),(2,3),(3,4),我想得到(1,2),(2,3),(3,4),(1,3)(2,4)这样的结果。

谢谢。

7 个回答

4

我们可以从一个“起始节点”开始,进行“闭包”操作。这个过程就是不断地把当前“端点”的“图边”合并,直到找不到新的端点为止。我们最多需要进行(节点数量 - 1)次这样的操作,因为这就是路径的最大长度。(这样做可以避免在有环的情况下陷入无限递归;虽然在一般情况下可能会浪费一些迭代,但可以省去检查我们是否完成的工作,也就是在某次迭代中没有做出任何改变。)

from collections import defaultdict

def transitive_closure(elements):
    edges = defaultdict(set)
    # map from first element of input tuples to "reachable" second elements
    for x, y in elements: edges[x].add(y)

    for _ in range(len(elements) - 1):
        edges = defaultdict(set, (
            (k, v.union(*(edges[i] for i in v)))
            for (k, v) in edges.items()
        ))

    return set((k, i) for (k, v) in edges.items() for i in v)

(我其实测试过一次 ;))

4

这是一个简单的尝试:

def transitive_closure(elements):
    elements = set([(x,y) if x < y else (y,x) for x,y in elements])

    relations = {}
    for x,y in elements:
        if x not in relations:
            relations[x] = []
        relations[x].append(y)

    closure = set()
    def build_closure(n):
        def f(k):
            for y in relations.get(k, []):
                closure.add((n, y))
                f(y)
        f(n)

    for k in relations.keys():
        build_closure(k)

    return closure

运行它后,我们会得到

In [3]: transitive_closure([(1,2),(2,3),(3,4)])
Out[3]: set([(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)])
13

没有内置的功能来处理传递闭包。

不过,实现起来其实很简单。

这是我的做法:

def transitive_closure(a):
    closure = set(a)
    while True:
        new_relations = set((x,w) for x,y in closure for q,w in closure if q == y)

        closure_until_now = closure | new_relations

        if closure_until_now == closure:
            break

        closure = closure_until_now

    return closure

调用: transitive_closure([(1,2),(2,3),(3,4)])

结果: set([(1, 2), (1, 3), (1, 4), (2, 3), (3, 4), (2, 4)])

调用: transitive_closure([(1,2),(2,1)])

结果: set([(1, 2), (1, 1), (2, 1), (2, 2)])

撰写回答