Python: удалите дубликаты кортежей из списка, если они точно такие же, включая порядок элементов

Я знаю, что подобные вопросы задавались много, много раз при переполнении стека, но мне нужно удалить дубликаты кортежей из списка, но не только, если их элементы совпадают, их элементы должны быть в том же порядке. Другими словами,(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).

6 ответов


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 будет удалить только точно дубликаты.


вам нужны уникальные перестановки, а не комбинации:

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

то есть, (1,2,2) и (2,1,2) будут рассматриваться как одна и та же комбинация, и только один из них будет возвращен. Однако это разные перестановки. Использовать set() удалить дубликаты.

Если после этого вы хотите отсортировать элементы внутри каждого кортежа, а также отсортировать весь список, вы можете сделать:

y = [tuple(sorted(q)) for q in y]
y.sort()

не нужно for цикл combinations дает генератор.

x = [1,1,1,2,2,2,3,3,3,4,4,5]
y = list(set(itertools.combinations(x,3)))

это, вероятно, сделает то, что вы хотите, но это огромный перебор. Это низкоуровневый прототип генератора, который мая добавил 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)

Вы были очень близки. Просто получите перестановки, а не комбинации. Порядок имеет значение в перестановках, а не в комбинациях. Таким образом, (1, 2, 2) является отличной перестановкой от (2, 2, 1). Однако (1, 2, 2) считается сингулярной комбинацией одного 1 и двух 2s. Поэтому (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))

С помощью set должны, вероятно, работать. Набор-это в основном контейнер, который не содержит дублированных элементов.

Python также включает тип данных для наборов. Набор является неупорядоченным коллекцию без повторяющихся элементов. Основные виды использования включают членство тестирование и устранение дубликатов записей. Set объекты также поддерживают математические операции, такие как объединение, пересечение, разность, и симметрическая разность.

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)