Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
传递闭包python元组_Python_Closures - Fatal编程技术网

传递闭包python元组

传递闭包python元组,python,closures,Python,Closures,有人知道是否有python内置的用于计算元组传递闭包的工具吗 我有形式为(1,2)、(2,3)、(3,4)的元组,我试图得到(1,2)、(2,3)、(3,4)、(1,3)(2,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:

有人知道是否有python内置的用于计算元组传递闭包的工具吗

我有形式为
(1,2)、(2,3)、(3,4)
的元组,我试图得到
(1,2)、(2,3)、(3,4)、(1,3)(2,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

传递闭包没有内置函数

不过,它们的实现非常简单

以下是我对它的看法:

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
电话: 传递闭包([(1,2)、(2,3)、(3,4)])

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

电话: 传递闭包([(1,2),(2,1)])

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

我们可以从给定的“开始节点”执行“闭合”操作,方法是从当前“端点”重复获取“图边”的并集,直到找不到新端点为止。我们最多需要这样做(节点数-1)次,因为这是路径的最大长度。(这样做可以避免在存在循环的情况下陷入无限递归;在一般情况下,这将浪费迭代,但可以避免检查我们是否完成的工作,即在给定迭代中没有进行任何更改。)


(我实际上测试过一次;)

次优,但概念上简单的解决方案:

def transitive_closure(a):
    closure = set()
    for x, _ in a:
        closure |= set((x, y) for y in dfs(x, a))
    return closure

def dfs(x, a):
    """Yields single elements from a in depth-first order, starting from x"""
    for y in [y for w, y in a if w == x]:
        yield y
        for z in dfs(y, a):
            yield z

当关系中存在一个循环,即自反点时,这将不起作用。

这里有一个与@soulcheck中的一个基本相同的循环,它适用于邻接列表而不是边列表:

def inplace_transitive_closure(g):
    """g is an adjacency list graph implemented as a dict of sets"""
    done = False
    while not done:
        done = True
        for v0, v1s in g.items():
            old_len = len(v1s)
            for v2s in [g[v1] for v1 in v1s]:
                v1s |= v2s
            done = done and len(v1s) == old_len

如果你有很多TUPEL(5000以上),你可能想考虑使用SIMPY代码来处理矩阵幂(也见)

在最好的情况下,如果你对你的关系/图有一点了解,你可以明智地选择
n
——这就是最长路径的长度。否则,您必须选择
M.shape[0]
,它可能会在您的脸上爆炸


这种迂回也有其局限性,特别是您应该确保闭包不会变得太大(连接性不是太强),但在python实现中也会遇到同样的问题。

您可以从这些元组创建一个图,然后从创建的图使用连接组件算法。是支持连接组件算法的库。

这里的“可传递”和“闭包”是什么意思?(1,3)和(2,4)的出现原理是什么?元组的长度总是一样的吗?“计算元组”是什么意思?更多关于传递闭包的内容。基本上,原则是如果在元组的原始列表中有两个元组,形式为
(a,b)
(c,z)
,并且
b
等于
c
,那么我们添加元组
(a,z)
元组将始终有两个条目,因为它是一个二进制关系。“计算元组”是指扩展元组的原始列表,使之成为可传递闭包。谢谢。我完全不知道这个概念。既然它出现了(2,4),那么(1,4)是否也应该出现在(1,2)和新的(2,4)中?如果有内置的东西,它就会出现,但它似乎不存在(内置的)。也许
关系
不是正确的名称;它只是为每个数字存储其他“可到达”的数字,构建一个DAG。递归函数
build\u closure
创建访问图的所有匹配项(此解决方案具有很强的输入假设,更灵活(和复杂)的输入可能更适合其他输入)[duh,注释已删除..将此答案留作参考]如果输入中存在循环,则将运行无限递归。(我第一次误解了代码,不知何故认为您在构建
关系时是在迭代成对的元素,而不是解包单个元素的元组)我希望
传递闭包([(1,2),(2,1)]
在输出中包括(像我一样)
(1,1)
(2,2)
,但我不知道OP到底想要什么…@KarlKnechtel:这就是传递性和反身性闭包。你说得对,karl。我刚刚点击了
RuntimeError:cmp中超过了最大递归深度,非常优雅。不要介意我之前的评论:)顺便说一句,
new_relations
严格地用集合论的术语来表示关系,或者用图的术语来表示边。在第二次调用的结果中我们不应该有
(2,2)
。@Duke是的,你应该(2,2)=(2,1)*(1,2)@Duke:如果xRy和yRz,那么R的传递闭包包括(x,z)。在这种情况下,x=z=2,y=1,所以应该包括(2,2)。这是Warshall算法吗?它在循环中会失败。@soulcheck:你说得对。证明;已经有很多更好的解决方案发布了。它很容易纠正,就像在典型的dfs中一样。看到循环后,返回创建循环的节点并回溯。
def transitive_closure(a):
    closure = set()
    for x, _ in a:
        closure |= set((x, y) for y in dfs(x, a))
    return closure

def dfs(x, a):
    """Yields single elements from a in depth-first order, starting from x"""
    for y in [y for w, y in a if w == x]:
        yield y
        for z in dfs(y, a):
            yield z
def inplace_transitive_closure(g):
    """g is an adjacency list graph implemented as a dict of sets"""
    done = False
    while not done:
        done = True
        for v0, v1s in g.items():
            old_len = len(v1s)
            for v2s in [g[v1] for v1 in v1s]:
                v1s |= v2s
            done = done and len(v1s) == old_len
from scipy.sparse import csr_matrix as csr
def get_closure(tups):
    index2id = list(set([tup[0] for tup in tups]) | set([tup[1] for tup in tups]));
    id2index = {index2id[i]:i for i in xrange(len(index2id))};
    tups_re  = tups + [(index2id[i],index2id[i],) for i in xrange(len(index2id))]; # Unfortunately you have to make the relation reflexive first - you could also add the diagonal to M
    M        = csr( ([True for tup in tups_re],([id2index[tup[0]] for tup in tups_re],[id2index[tup[1]] for tup in tups_re])),shape=(len(index2id),len(index2id)),dtype=bool);
    M_       = M**n; # n is maximum path length of your relation
    temp     = M_.nonzero();
    #TODO: You might want to remove the added reflexivity tupels again
    return [(index2id[temp[0][i]],index2id[temp[1][i]],) for i in xrange(len(temp[0]))];