从python中的列表列表中删除类似但不相同的列表

时间:2012-09-13 13:52:09

标签: python graph graph-theory

我正在识别方向图中的循环。我的函数返回一个列表列表,用于存储找到的任何循环中的节点。

例如,在节点连接如下的图表中:

(1,2)(2,3)(3,4)(3,5)(5,2)

在2 - 3 - 5处找到一个循环,因此该函数将返回:

[[2,3,5]]

有些情况下会有多个循环会返回类似的内容:

[[2,3,4][6,7,8,9]]

这很好,但是如果图中有多个起始点在不同的点连接相同的循环,例如图中:

(1,2)(2,3)(3,4)(3,5)(5,2)(6,3)

节点1和节点6在不同的点处连接相同的循环,这将返回:

[[2,3,5][3,5,2]]

所以这里有两个相同的循环,它们不是相同的列表。我想确定这样的重复并删除除了一个之外的所有重复(无关紧要)。

注意,可能存在多个循环的情况,其中一个是重复的,例如:

[[2,3,5][3,5,2][7,8,9,6]]

我试过调查itertools:

loops.sort()
list(loops for loops,_ in itertools.groupby(loops))

但这没有帮助,而且我不能100%确定这是否合适。有任何想法吗?我在python 2.4上。谢谢你的帮助。

3 个答案:

答案 0 :(得分:3)

如果你只关心每个循环的元素而不是顺序,我会通过对每个循环进行排序来规范化每个循环,然后使用集合:

>>> loops = [[2,3,5],[3,5,2],[7,8,9,6]]
>>> set(tuple(sorted(loop)) for loop in loops)
set([(2, 3, 5), (6, 7, 8, 9)])

要在此处使用set,您需要转换为元组。您可以将元组转换回列表,或者将最终集合转换回列表(甚至可以使用sorted来获取规范顺序),但是您是否真的需要依赖于您的内容用它来做。

如果你需要保留路径顺序,我会以不同的方式规范化:

def rotated(l, n):
    return l[n:] + l[:n]

def canonicalize(l):
    m = min(l)
    where = l.index(m)
    return rotated(l, where)

然后

>>> loops = [[2,5,3], [5,3,2], [7,8,6,9]]
>>> set(tuple(canonicalize(loop)) for loop in loops)
set([(2, 5, 3), (6, 9, 7, 8)])

[编辑:请注意,这个简单的规范化只有在每个顶点只能在路径中访问一次时才有效。]

答案 1 :(得分:1)

首先,您需要定义相似之处,因为它比set更强:

def is_similar(X,Y):
    n = len(X)
    return len(Y) == n and any( all( X[i] == Y[(i+j)%n] 
                                     for i in range(n) )
                                for j in range(1,n) ) #the 1 here so that identical lists are not similar

区别很重要,因为路径(1,2,3,4)与路径(1,3,2,4)不同,它们不对应于同一个循环。

def remove_similars(L):
     new_L = []
     for item in L:
         if not any( is_similar(item, l) for l in new_L ):
             new_L.append(item)
     return new_L

答案 2 :(得分:0)

您可以获取每个列表的set。如果两个集合相等,那么您有一个重复的循环。但是,您正在丢失循环中节点的顺序,但这对您来说很重要吗?