上下文 - 开发算法以确定潮流网络中的循环流。
问题:
我有一个列表列表,每个列表代表通过我的算法确定的网络内的循环。不幸的是,该算法也将获得反向重复。
即。
L1 = [a, b, c, -d, -a]
L2 = [a, d, c, -b, -a]
(请注意,c不应该是负数,由于网络的结构和定义的流程,它是正确的)
现在这两个循环是等效的,只是遵循整个网络的反向结构。
我希望保留L1,同时从列表列表中丢弃L2。 因此,如果我有一个包含6个循环的列表,其中3个是反向重复,我希望保留所有三个循环。
此外,循环不必遵循上面指定的格式。它可以更短,更长,并且在所有情况下都不会出现符号结构(例如pos pos pos neg neg)。
我一直试图通过反转列表并比较绝对值来对此进行排序。
我感到非常难过,我们将不胜感激。
根据mgibson提供的一些代码,我能够创建以下内容。
def Check_Dup(Loops):
Act = []
while Loops:
L = Loops.pop()
Act.append(L)
Loops = Popper(Loops, L)
return Act
def Popper(Loops, L):
for loop in Loops:
Rev = loop[::-1]
if all (abs(x) == abs(y) for x, y in zip(loop_check, Rev)):
Loops.remove(loop)
return Loops
此代码应该运行,直到每次都没有丢弃重复项的循环。我接受了mgibsons的答案,因为它提供了创建解决方案的必要钥匙
答案 0 :(得分:1)
我不确定我是否提出了您的问题,但撤消列表很容易:
a = [1,2]
a_rev = a[::-1] #new list -- if you just want an iterator, reversed(a) also works.
比较a
和a_rev
的绝对值:
all( abs(x) == abs(y) for x,y in zip(a,a_rev) )
可以简化为:
all( abs(x) == abs(y) for x,y in zip(a,reversed(a)) )
现在,为了使其尽可能高效,我首先会根据绝对值对数组进行排序:
your_list_of_lists.sort(key = lambda x : map(abs,x) )
现在您知道如果两个列表相同,它们必须在列表中相邻,您可以使用枚举来实现它:
def cmp_list(x,y):
return True if x == y else all( abs(a) == abs(b) for a,b in zip(a,b) )
duplicate_idx = [ idx for idx,val in enumerate(your_list_of_lists[1:])
if cmp_list(val,your_list_of_lists[idx]) ]
#now remove duplicates:
for idx in reversed(duplicate_idx):
_ = your_list_of_lists.pop(idx)
如果您的(子)列表严格增加或严格减少,则 MUCH 更简单。
lists = list(set( tuple(sorted(x)) for x in your_list_of_lists ) )
答案 1 :(得分:0)
[pair[0] for pair in frozenset(sorted( (c,negReversed(c)) ) for c in cycles)]
其中:
def negReversed(list):
return tuple(-x for x in list[::-1])
并且cycles
必须是元组。
这需要每个周期,计算它的副本,然后对它们进行排序(将它们放在一个规范等价的对中)。集合frozenset(...)
取消任何重复。然后你提取规范元素(在这种情况下,我任意选择它为pair[0])
。
请记住,您的算法可能会返回从任意位置开始的循环。如果是这种情况(即您的算法可能返回[1,2,-3]
或[-3,1,2]
),那么你需要将它们视为等效的necklaces
有很多方法可以规范化项链。上述方法效率较低,因为我们不关心直接规范化项链:我们只需将整个等价类视为规范元素,将每个循环(a,b,c,d,e)
转换为{(a,b,c,d,e), (e,a,b,c,d), (d,e,a,b,c), (c,d,e,a,b), (b,c,d,e,a)}
。在您的情况下,因为您认为负数是等价的,您可以将每个周期变为{(a,b,c,d,e), (e,a,b,c,d), (d,e,a,b,c), (c,d,e,a,b), (b,c,d,e,a), (-a,-b,-c,-d,-e), (-e,-a,-b,-c,-d), (-d,-e,-a,-b,-c), (-c,-d,-e,-a,-b), (-b,-c,-d,-e,-a)}
。请务必使用frozenset
来提高效果,因为set
不可用:
eqClass.pop() for eqClass in {frozenset(eqClass(c)) for c in cycles}
其中:
def eqClass(cycle):
for rotation in rotations(cycle):
yield rotation
yield (-x for x in rotation)
其中,旋转类似于Efficient way to shift a list in python但产生元组
答案 2 :(得分:0)
如果您在两个方向都c
,我看不出它们是如何相等的 - 其中一个必须是-c
>>> a,b,c,d = range(1,5)
>>> L1 = [a, b, c, -d, -a]
>>> L2 = [a, d, -c, -b, -a]
>>> L1 == [-x for x in reversed(L2)]
True
现在您可以编写一个函数将这两个循环折叠为单个值
>>> def normalise(loop):
... return min(loop, [-x for x in reversed(L2)])
...
>>> normalise(L1)
[1, 2, 3, -4, -1]
>>> normalise(L2)
[1, 2, 3, -4, -1]
消除重复的一个好方法是使用一个集合,我们只需要将列表转换为元组
>>> L=[L1, L2]
>>> set(tuple(normalise(loop)) for loop in L)
set([(1, 2, 3, -4, -1)])