[英]Removing similar, but not identical, lists from a list of lists in python
我正在確定方向圖中的循環。 我的函數返回一個列表列表,該列表將節點存儲在找到的任何循環中。
例如在圖中這樣連接節點的圖中:
(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上。 謝謝你的幫助。
如果您只關心每個循環的元素而不是順序,那么我將通過對每個循環進行排序來規范化每個循環,然后采用集合:
>>> 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)])
[編輯:請注意,只有在路徑中每個頂點只能訪問一次時,這種簡單的規范化才有效。
首先,您需要定義相似之處,因為它比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
您可以選擇每個列表中的一set
。 如果兩組相等,則您有一個重復的循環。 您雖然失去了循環中節點的順序,但這對您來說重要嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.