我正在识别方向图中的循环。我的函数返回一个列表列表,用于存储找到的任何循环中的节点。
例如,在节点连接如下的图表中:
(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上。谢谢你的帮助。
答案 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
。如果两个集合相等,那么您有一个重复的循环。但是,您正在丢失循环中节点的顺序,但这对您来说很重要吗?