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)
.
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 .
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()
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)))
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)
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é. :)
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)