web-dev-qa-db-fra.com

Supprimer les tuples en double d'une liste s'ils sont exactement les mêmes, y compris l'ordre des éléments

Je sais que des questions similaires à celles-ci ont été posées de nombreuses fois sur Stack Overflow, mais je dois supprimer les tuples en double d'une liste, mais pas seulement si leurs éléments correspondent, leurs éléments doivent être dans le même ordre. En d'autres termes, (4,3,5) et (3,4,5) serait tous les deux présents dans la sortie, alors que s'il y avait les deux(3,3,5) et (3,3,5), un seul serait dans la sortie.

Plus précisément, mon code est:

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)

dont la sortie est assez longue. Par exemple, dans la sortie, il doit y avoir à la fois (1,2,1) et (1,1,2). Mais il ne devrait y en avoir qu'un (1,2,2).

17
5813

set s'en occupera:

>>> 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 supprimera uniquement les doublons exacts .

33
user2555451

Vous avez besoin de permutations uniques plutôt que de combinaisons:

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

Autrement dit, (1,2,2) et (2,1,2) seront considérés comme la même combinaison et un seul d'entre eux sera retourné. Ce sont cependant des permutations différentes. Utilisez set() pour supprimer les doublons.

Si, par la suite, vous souhaitez trier des éléments dans chaque Tuple et que la liste entière soit également triée, vous pouvez faire:

y = [Tuple(sorted(q)) for q in y]
y.sort()
2
sashkello

Pas besoin de faire for boucle, combinations donne un générateur.

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

Cela fera probablement ce que vous voulez, mais c'est une énorme exagération. C'est un prototype de bas niveau pour un générateur qui peut être ajouté à itertools un jour. C'est un niveau bas pour faciliter sa réimplémentation en C. Où N est la longueur de l'entrée itérable, il nécessite le pire des espaces O(N) et fait tout au plus N*(N-1)//2 comparaisons d'éléments, quel que soit le nombre d'anagrammes générés. Les deux sont optimaux ;-)

Vous l'utiliseriez comme ceci:

>>> 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)
...

Il n'y aura pas de doublons dans la sortie. Remarque: il s'agit du code Python 3. Il a besoin de quelques modifications pour s'exécuter sous 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
Tim Peters

Tu étais vraiment proche. Obtenez juste des permutations, pas des combinaisons. L'ordre est important par permutations, et non par combinaisons. Ainsi (1, 2, 2) est une permutation distincte de (2, 2, 1). Cependant (1, 2, 2) est considéré comme une combinaison singulière d'un 1 et de deux 2. Par conséquent, (2, 2, 1) n'est pas considéré comme une combinaison distincte de (1, 2, 2).

Vous pouvez convertir votre liste y en un ensemble afin de supprimer les doublons ...

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))

Et voila, vous avez terminé. :)

1
Shashank

L'utilisation d'un set devrait probablement fonctionner. Un ensemble est essentiellement un conteneur qui ne contient aucun élément en double.

Python inclut également un type de données pour les ensembles. Un ensemble est une collection non ordonnée sans éléments en double. Les utilisations de base incluent le test d'adhésion et l'élimination des entrées en double. Les objets set prennent également en charge les opérations mathématiques comme l'union, l'intersection, la différence et la différence symétrique.

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)
0
TankorSmash