Dans cette réponse, il y aura deux sections: deux solutions uniques et un graphique de vitesse pour des solutions spécifiques.
Suppression des éléments en double
La plupart de ces réponses ne suppriment que les éléments en double qui sont lavables , mais cette question n'implique pas qu'il n'a pas seulement besoin d' éléments lavables , ce qui signifie que je proposerai des solutions qui ne nécessitent pas de nettoyage. articles .
collections.Counter est un outil puissant dans la bibliothèque standard qui pourrait être parfait pour cela. Il n'y a qu'une seule autre solution qui contient même Counter. Cependant, cette solution est également limitée à hashable clés .
Pour autoriser les clés non partageables dans Counter, j'ai créé une classe Container, qui essaiera d'obtenir la fonction de hachage par défaut de l'objet, mais si elle échoue, elle essaiera sa fonction d'identité. Il définit également un eq et une méthode de hachage . Cela devrait être suffisant pour autoriser les éléments non lavables dans notre solution. Les objets non lavables seront traités comme s'ils étaient lavables. Cependant, cette fonction de hachage utilise l'identité pour les objets non lavables, ce qui signifie que deux objets égaux qui sont tous les deux non lavables ne fonctionneront pas. Je vous suggère de remplacer cela et de le changer pour utiliser le hachage d'un type mutable équivalent (comme utiliser hash(tuple(my_list))
ifmy_list
est une liste).
J'ai également fait deux solutions. Une autre solution qui conserve l'ordre des articles, en utilisant une sous-classe à la fois OrderedDict et Counter qui est nommée 'OrderedCounter'. Maintenant, voici les fonctions:
from collections import OrderedDict, Counter
class Container:
def __init__(self, obj):
self.obj = obj
def __eq__(self, obj):
return self.obj == obj
def __hash__(self):
try:
return hash(self.obj)
except:
return id(self.obj)
class OrderedCounter(Counter, OrderedDict):
'Counter that remembers the order elements are first encountered'
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
def __reduce__(self):
return self.__class__, (OrderedDict(self),)
def remd(sequence):
cnt = Counter()
for x in sequence:
cnt[Container(x)] += 1
return [item.obj for item in cnt]
def oremd(sequence):
cnt = OrderedCounter()
for x in sequence:
cnt[Container(x)] += 1
return [item.obj for item in cnt]
remd est un tri non ordonné, oremd est un tri ordonné. Vous pouvez clairement dire lequel est le plus rapide, mais je l'expliquerai quand même. Le tri non ordonné est légèrement plus rapide. Il conserve moins de données, car il n'a pas besoin de commande.
Maintenant, je voulais aussi montrer les comparaisons de vitesse de chaque réponse. Donc, je vais le faire maintenant.
Quelle fonction est la plus rapide?
Pour supprimer les doublons, j'ai rassemblé 10 fonctions à partir de quelques réponses. J'ai calculé la vitesse de chaque fonction et l'ai mise dans un graphique en utilisant matplotlib.pyplot .
J'ai divisé cela en trois séries de graphiques. Un hachable est tout objet qui peut être haché, un non lavable est tout objet qui ne peut pas être haché. Une séquence ordonnée est une séquence qui préserve l'ordre, une séquence non ordonnée ne préserve pas l'ordre. Maintenant, voici quelques termes supplémentaires:
Unordered Hashable était pour toute méthode qui supprimait les doublons, qui ne devait pas nécessairement conserver la commande. Cela ne devait pas fonctionner pour les incontrôlables, mais cela pouvait.
Commandé Hashable était pour n'importe quelle méthode qui gardait l'ordre des articles dans la liste, mais cela ne devait pas fonctionner pour les éléments non modifiables, mais c'était possible.
Ordered Unhashable était une méthode qui maintenait l'ordre des éléments dans la liste et fonctionnait pour les éléments non partageables.
Sur l'axe des y est le nombre de secondes qu'il a fallu.
Sur l'axe des x se trouve le nombre auquel la fonction a été appliquée.
Nous avons généré des séquences de hashables non ordonnées et ordonnées hashables avec la compréhension suivante: [list(range(x)) + list(range(x)) for x in range(0, 1000, 10)]
Pour les éléments non partagés commandés: [[list(range(y)) + list(range(y)) for y in range(x)] for x in range(0, 1000, 10)]
Notez qu'il y a une «étape» dans la plage, car sans elle, cela aurait pris 10 fois plus de temps. Aussi parce qu'à mon avis, je pensais que ça aurait pu paraître un peu plus facile à lire.
Notez également que les touches de la légende sont ce que j'ai essayé de deviner comme les parties les plus vitales de la fonction. Quant à quelle fonction fait le pire ou le meilleur? Le graphique parle de lui-même.
Avec cela réglé, voici les graphiques.
Hashables non ordonnés
(Zoomé)
Hashables commandés
(Zoomé)
Unhashables commandés
(Zoomé)