20

我知道在 Stack Overflow 上已经多次提出过类似的问题,但我需要从列表中删除重复的元组,但不仅仅是它们的元素匹配,它们的元素必须按相同的顺序排列。换句话说,(4,3,5)(3,4,5)都将出现在输出中,而如果同时存在(3,3,5)(3,3,5),则只有一个出现在输出中。

具体来说,我的代码是:

import itertools

x = [1,1,1,2,2,2,3,3,3,4,4,5]
y = []

for x in itertools.combinations(x,3):
    y.append(x)
print(y)

其中输出相当长。例如,在输出中,应该有(1,2,1)(1,1,2)。但应该只有一个(1,2,2)

4

6 回答 6

37

set会处理的:

>>> a = [(1,2,2), (2,2,1), (1,2,2), (4,3,5), (3,3,5), (3,3,5), (3,4,5)]
>>> set(a)
set([(1, 2, 2), (2, 2, 1), (3, 4, 5), (3, 3, 5), (4, 3, 5)])
>>> list(set(a))
[(1, 2, 2), (2, 2, 1), (3, 4, 5), (3, 3, 5), (4, 3, 5)]
>>>

set只会删除完全相同的重复项。

于 2013-10-17T01:32:08.957 回答
3

您需要的是独特的排列而不是组合:

y = list(set(itertools.permutations(x,3)))

也就是说,(1,2,2) 和 (2,1,2) 将被视为相同的组合,并且只会返回其中一个。然而,它们是不同的排列。用于set()删除重复项。

如果之后您想对每个元组中的元素进行排序并且还对整个列表进行排序,您可以执行以下操作:

y = [tuple(sorted(q)) for q in y]
y.sort()
于 2013-10-17T01:37:08.600 回答
1

无需for循环,combinations提供生成器。

x = [1,1,1,2,2,2,3,3,3,4,4,5]
y = list(set(itertools.combinations(x,3)))
于 2013-10-17T01:35:04.223 回答
1

这可能会做你想要的,但它是巨大的矫枉过正。这是一个生成器的低级原型,可能会在itertools某一天添加​​。易于在 C 中重新实现它是低级的。N可迭代输入的长度在哪里,它需要最坏情况的空间O(N)并且最多N*(N-1)//2进行元素比较,而不管生成了多少字谜。这两个都是最佳的;-)

你会像这样使用它:

>>> x = [1,1,1,2,2,2,3,3,3,4,4,5]
>>> for t in anagrams(x, 3):
...     print(t)
(1, 1, 1)
(1, 1, 2)
(1, 1, 3)
(1, 1, 4)
(1, 1, 5)
(1, 2, 1)
...

输出中不会有重复项。注意:这是 Python 3 代码。它需要一些更改才能在 Python 2 下运行。

import operator

class ENode:
    def __init__(self, initial_index=None):
        self.indices = [initial_index]
        self.current = 0
        self.prev = self.next = self

    def index(self):
        "Return current index."
        return self.indices[self.current]

    def unlink(self):
        "Remove self from list."
        self.prev.next = self.next
        self.next.prev = self.prev

    def insert_after(self, x):
        "Insert node x after self."
        x.prev = self
        x.next = self.next
        self.next.prev = x
        self.next = x

    def advance(self):
        """Advance the current index.

        If we're already at the end, remove self from list.

        .restore() undoes everything .advance() did."""

        assert self.current < len(self.indices)
        self.current += 1
        if self.current == len(self.indices):
            self.unlink()

    def restore(self):
        "Undo what .advance() did."
        assert self.current <= len(self.indices)
        if self.current == len(self.indices):
            self.prev.insert_after(self)
        self.current -= 1

def build_equivalence_classes(items, equal):
    ehead = ENode()
    for i, elt in enumerate(items):
        e = ehead.next
        while e is not ehead:
            if equal(elt, items[e.indices[0]]):
                # Add (index of) elt to this equivalence class.
                e.indices.append(i)
                break
            e = e.next
        else:
            # elt not equal to anything seen so far:  append
            # new equivalence class.
            e = ENode(i)
            ehead.prev.insert_after(e)
    return ehead

def anagrams(iterable, count=None, equal=operator.__eq__):
    def perm(i):
        if i:
            e = ehead.next
            assert e is not ehead
            while e is not ehead:
                result[count - i] = e.index()
                e.advance()
                yield from perm(i-1)
                e.restore()
                e = e.next
        else:
            yield tuple(items[j] for j in result)

    items = tuple(iterable)
    if count is None:
        count = len(items)
    if count > len(items):
        return

    ehead = build_equivalence_classes(items, equal)
    result = [None] * count
    yield from perm(count)
于 2013-10-17T01:51:49.250 回答
1

你真的很亲近。只得到排列,而不是组合。顺序在排列中很重要,而在组合中则不重要。因此 (1, 2, 2) 是与 (2, 2, 1) 不同的排列。然而 (1, 2, 2) 被认为是一个 1 和两个 2 的奇异组合。因此 (2, 2, 1) 不被视为与 (1, 2, 2) 不同的组合。

您可以将列表 y 转换为集合,以便删除重复项...

import itertools

x = [1,1,1,2,2,2,3,3,3,4,4,5]
y = []

for x in itertools.permutations(x,3):
    y.append(x)
print(set(y))

瞧,你完成了。:)

于 2013-10-17T01:58:00.410 回答
0

使用一套应该可以工作。集合基本上是一个不包含任何重复元素的容器。

Python 还包括集合的数据类型。集合是没有重复元素的无序集合。基本用途包括成员资格测试和消除重复条目。集合对象还支持联合、交集、差分和对称差分等数学运算。

import itertools

x = [1,1,1,2,2,2,3,3,3,4,4,5]
y = set()

for x in itertools.combinations(x,3):
    y.add(x)
print(y)
于 2013-10-17T01:32:30.843 回答