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

Я знаю, что подобные вопросы были заданы много раз в 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).

Ответ 1

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

Ответ 2

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

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

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

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

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

Ответ 3

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

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

Ответ 4

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

Ответ 5

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

И вуаля, все готово.:)

Ответ 6

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

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)