1

我昨天问了一个问题,感谢蒂姆彼得斯,它已经解决了。问题就在这里;

itertools.product 消除重复元素

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

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)

谢谢,

4

2 回答 2

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))
于 2013-11-03T15:39:53.333 回答
1

问题是您无条件地这样做reverse.remove(rvrs),即使rvrs在您(冗余地)添加它之前已经存在。reverse所以插入:

            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]
于 2013-11-03T19:41:31.777 回答