itertools.product消除重复的反转元组

时间:2013-11-03 15:18:32

标签: python python-2.7 itertools

昨天我问了一个问题,感谢Tim Peters,它已经解决了。问题在这里;

itertools.product eliminating repeated elements

新问题是这个的进一步版本。这次我将在元组内部生成元组。这是一个例子;

lis = [[(1,2), (3,4)], [(5,2), (1,2)], [(2,1), (1,2)]]

当我在itertools.product函数中使用它时,这就是我得到的,

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

我想以一种方式改变它,如果一个序列在其中有(a,b),那么它就不能有(b,a)。在这个例子中,如果你看一下这个序列((3, 4), (1, 2), (2, 1)),它里面有(1,2)和(2,1)。因此,结果中不应考虑此序列((3, 4), (1, 2), (2, 1))

正如我所说,之前我曾问过类似的问题,在这种情况下,它没有考虑重复的元素。我试着让它适应我的问题。这是修改后的代码。旧版本中的更改部分将在评论中进行。

def reverse_seq(seq):
    s = []
    for i in range(len(seq)):
        s.append(seq[-i-1])         
    return tuple(s)


def uprod(*seqs):  
    def inner(i):
        if i == n:
            yield tuple(result)
            return
        for elt in sets[i] - reverse:
            #seen.add(elt)
            rvrs = reverse_seq(elt)
            reverse.add(rvrs)
            result[i] = elt
            for t in inner(i+1):
                yield t
            #seen.remove(elt)
            reverse.remove(rvrs)

    sets = [set(seq) for seq in seqs]
    n = len(sets)
    #seen = set()
    reverse = set()
    result = [None] * n
    for t in inner(0):
        yield t

在我看来,这段代码应该可以正常工作,但输入lis = [[(1,2), (3,4)], [(5,2), (1,2)], [(2,1), (1,2)]]会出错。我无法理解我错在哪里。

for i in uprod(*lis):
    print i

输出是,

((1, 2), (1, 2), (1, 2))
Traceback (most recent call last):
  File "D:\Users\SUUSER\workspace tree\sequence_covering _array\denemeler_buraya.py", line 39, in <module>
    for i in uprod(*lis):
  File "D:\Users\SUUSER\workspace tree\sequence_covering _array\denemeler_buraya.py", line 32, in uprod
    for t in inner(0):
  File "D:\Users\SUUSER\workspace tree\sequence_covering _array\denemeler_buraya.py", line 22, in inner
    for t in inner(i+1):
  File "D:\Users\SUUSER\workspace tree\sequence_covering _array\denemeler_buraya.py", line 25, in inner
    reverse.remove(rvrs)
KeyError: (2, 1)

谢谢,

2 个答案:

答案 0 :(得分:1)

我的做法有点不同,使用套装来摆脱不需要订单的顺序。实际上使用frozensets,所以我们可以很容易地嵌套它们。

首先,我们将lis转换为(冻结)集的列表列表,因为应忽略元组数的顺序。

>>> lis = [[(1,2), (3,4)], [(5,2), (1,2)], [(2,1), (1,2)]]
>>> lis_ = [[frozenset(x) for x in y] for y in lis]

接下来,我们创建产品,然后将结果放在一个集合中,这样我们就可以摆脱重复:

>>> result = set(x for x in itertools.product(*lis_))
>>> result
{(frozenset({3, 4}), frozenset({1, 2}), frozenset({1, 2})), (frozenset({1, 2}), frozenset({1, 2}), frozenset({1, 2})), (frozenset({3, 4}), frozenset({2, 5}), frozenset({1, 2})), (frozenset({1, 2}), frozenset({2, 5}), frozenset({1, 2}))}

我们已经完成了。如果你现在打印它们,并使它更漂亮(摆脱输出中的frozenset()部分,你得到你的结果:

>>> for r in result:
        print([tuple(x) for x in r])

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

只是过滤itertools.product的结果的不同解决方案:

>>> lis = [[(1,2), (3,4)], [(5,2), (1,2)], [(2,1), (1,2)]]
>>> seenProducts = set()
>>> for p in itertools.product(*lis):
        product = tuple(frozenset(x) for x in p)
        if product not in seenProducts:
            seenProducts.add(product)
            print(p) # print original product

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

答案 1 :(得分:1)

问题是,在您(冗余地)添加reverse.remove(rvrs) rvrs之前,reverse已经<{1}}无条件执行 remove_later = rvrs not in reverse 。所以插入:

            reverse.add(rvrs)

之前:

            if remove_later:
                reverse.remove(rvrs)

并将删除代码更改为:

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

然后输出是:

reverse_seq()

无关紧要,您可以丢弃 rvrs = elt[::-1] 函数并改为编写:

{{1}}