按唯一反向绝对条件对列表列表进行排序

时间:2012-08-22 23:41:21

标签: python list sorting duplicates

上下文 - 开发算法以确定潮流网络中的循环流。

问题:

我有一个列表列表,每个列表代表通过我的算法确定的网络内的循环。不幸的是,该算法也将获得反向重复。

即。

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的答案,因为它提供了创建解决方案的必要钥匙

3 个答案:

答案 0 :(得分:1)

我不确定我是否提出了您的问题,但撤消列表很容易:

a = [1,2]
a_rev = a[::-1]  #new list -- if you just want an iterator, reversed(a) also works.

比较aa_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)])