Suppression des doublons dans les listes

998

À peu près, j'ai besoin d'écrire un programme pour vérifier si une liste contient des doublons et s'il le fait, il les supprime et renvoie une nouvelle liste avec les éléments qui n'ont pas été dupliqués / supprimés. C'est ce que j'ai mais pour être honnête je ne sais pas quoi faire.

def remove_duplicates():
    t = ['a', 'b', 'c', 'd']
    t2 = ['a', 'c', 'd']
    for t in t2:
        t.append(t.remove())
    return t
Neemaximo
la source
22
Votre description indique que vous vérifiez "une liste" pour les doublons, mais votre code vérifie deux listes.
Brendan Long
* en utilisant set: list (set (ELEMENTS_LIST)) * en utilisant le dictionnaire: list (dict.fromkeys (ELEMENTS_LIST))
Shayan Amani

Réponses:

1643

L'approche courante pour obtenir une collection unique d'articles est d'utiliser a set. Les ensembles sont des collections non ordonnées d' objets distincts . Pour créer un ensemble à partir de n'importe quel itérable, vous pouvez simplement le passer à la set()fonction intégrée. Si vous avez besoin ultérieurement d'une vraie liste, vous pouvez également transmettre l'ensemble à la list()fonction.

L'exemple suivant doit couvrir tout ce que vous essayez de faire:

>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> list(set(t))
[1, 2, 3, 5, 6, 7, 8]
>>> s = [1, 2, 3]
>>> list(set(t) - set(s))
[8, 5, 6, 7]

Comme vous pouvez le voir dans l'exemple de résultat, la commande d'origine n'est pas conservée . Comme mentionné ci-dessus, les ensembles eux-mêmes sont des collections non ordonnées, donc la commande est perdue. Lors de la reconversion d'un ensemble en liste, un ordre arbitraire est créé.

Maintenir l'ordre

Si l'ordre est important pour vous, vous devrez utiliser un mécanisme différent. Une solution très courante pour cela consiste à s'appuyer sur OrderedDictpour conserver l'ordre des clés lors de l'insertion:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

À partir de Python 3.7 , le dictionnaire intégré est également garanti de maintenir l'ordre d'insertion, vous pouvez donc également l'utiliser directement si vous êtes sur Python 3.7 ou version ultérieure (ou CPython 3.6):

>>> list(dict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

Notez que cela peut entraîner une surcharge de création d'un dictionnaire, puis de création d'une liste à partir de celui-ci. Si vous n'avez pas réellement besoin de conserver l'ordre, il vaut souvent mieux utiliser un ensemble, surtout parce qu'il vous donne beaucoup plus d'opérations avec lesquelles travailler. Consultez cette question pour plus de détails et d'autres moyens de préserver l'ordre lors de la suppression des doublons.


Enfin, notez que les solutions setaussi bien que OrderedDict/ dictnécessitent que vos articles soient lavables . Cela signifie généralement qu'ils doivent être immuables. Si vous devez gérer des éléments qui ne sont pas hachables (par exemple, lister des objets), vous devrez utiliser une approche lente dans laquelle vous devrez essentiellement comparer chaque élément avec tous les autres éléments dans une boucle imbriquée.

poussée
la source
4
Cela ne fonctionne pas pour les éléments de liste non partageables (par exemple une liste de listes)
KNejad
3
@KNejad C'est ce que dit le dernier paragraphe.
poke
Oh oups. Aurait dû lire le tout. Ce que j'ai fini par faire était d'utiliser des tuples au lieu de listes pour que cette approche puisse toujours fonctionner.
KNejad
ajoutez ceci à l'exemple, t = [3, 2, 1, 1, 2, 5, 6, 7, 8], montre clairement la différence!
sailfish009
"... frais généraux de création d'un dictionnaire d'abord ... Si vous n'avez pas vraiment besoin de conserver l'ordre, il vaut mieux utiliser un ensemble." - J'ai profilé cela parce que j'étais curieux de savoir si c'était vraiment vrai. Mes timings montrent qu'en effet l'ensemble est légèrement plus rapide: 1,12 µs par boucle (set) vs 1,53 µs par boucle (dict) sur 1M de boucles avec une différence de temps absolue d'environ 4s sur 1M d'itérations. Donc, si vous faites cela dans une boucle intérieure serrée, vous pouvez vous en soucier, sinon probablement pas.
millerdev
414

Dans Python 2.7 , la nouvelle façon de supprimer les doublons d'un itérable tout en le conservant dans l'ordre d'origine est:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

Dans Python 3.5 , OrderedDict a une implémentation C. Mes synchronisations montrent que c'est maintenant à la fois la plus rapide et la plus courte des différentes approches pour Python 3.5.

En Python 3.6 , le dict régulier est devenu à la fois ordonné et compact. (Cette fonctionnalité est valable pour CPython et PyPy mais peut ne pas être présente dans d'autres implémentations). Cela nous donne un nouveau moyen de déduplication le plus rapide tout en conservant l'ordre:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

Dans Python 3.7 , le dict régulier est garanti à la fois ordonné dans toutes les implémentations. Ainsi, la solution la plus courte et la plus rapide est:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
Raymond Hettinger
la source
10
Je pense que c'est la seule façon de garder les articles en ordre.
Herberth Amaral
19
@HerberthAmaral: C'est très loin d'être vrai, voir Comment supprimer les doublons d'une liste en Python tout en préservant l'ordre?
Martijn Pieters
5
@MartijnPieters Correction: Je pense que c'est le seul moyen simple de garder les articles en ordre.
Herberth Amaral
12
Pour cela aussi, le contenu de la liste originale doit être lavable
Davide
Comme @Davide l'a mentionné, la liste d'origine doit être hachable. Cela signifie que cela ne fonctionne pas pour une liste de dictionnaires. TypeError: unhashable type: 'dictlist'
CraZ
187

C'est un vol simple: list(set(source_list))fera l'affaire.

A setest quelque chose qui ne peut pas avoir de doublons.

Mise à jour: une approche qui préserve l'ordre est de deux lignes:

from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()

Ici, nous utilisons le fait qui se OrderedDictsouvient de l'ordre d'insertion des clés et ne le change pas lorsqu'une valeur à une clé particulière est mise à jour. Nous insérons en Truetant que valeurs, mais nous pourrions insérer n'importe quoi, les valeurs ne sont tout simplement pas utilisées. ( setfonctionne un peu comme un dictavec des valeurs ignorées aussi.)

9000
la source
5
Cela ne fonctionne que si source_listest lavable.
Adrian Keister
@AdrianKeister: C'est vrai. Il existe des objets qui ont une sémantique d'égalité raisonnable mais qui ne sont pas hachables, par exemple des listes. OTOH si nous ne pouvons pas avoir un raccourci comme un hastable, nous nous retrouvons avec un algorithme quadratique de comparaison de chaque élément avec tous les éléments uniques actuellement connus. Cela peut être totalement OK pour les entrées courtes, en particulier avec beaucoup de doublons.
9000
Exactement. Je pense que votre réponse serait de meilleure qualité si vous preniez en compte ce cas d'utilisation très courant.
Adrian Keister
95
>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> s = []
>>> for i in t:
       if i not in s:
          s.append(i)
>>> s
[1, 2, 3, 5, 6, 7, 8]
Neeraj
la source
33
Notez que cette méthode fonctionne en temps O (n ^ 2) et est donc très lente sur les grandes listes.
dotancohen
@Chris_Rands: Je ne suis pas sûr que cela frozensetfonctionne avec du contenu non hachable. J'obtiens toujours l'erreur non-hachable lors de l'utilisation frozenset.
Adrian Keister
85

Si vous ne vous souciez pas de la commande, faites simplement ceci:

def remove_duplicates(l):
    return list(set(l))

A setest garanti de ne pas avoir de doublons.

Brendan Long
la source
3
Ne fonctionne que s'il lest lavable.
Adrian Keister
41

Pour créer une nouvelle liste en conservant l'ordre des premiers éléments des doublons dans L

newlist=[ii for n,ii in enumerate(L) if ii not in L[:n]]

par exemple if L=[1, 2, 2, 3, 4, 2, 4, 3, 5]alorsnewlist sera[1,2,3,4,5]

Ceci vérifie que chaque nouvel élément n'est pas apparu précédemment dans la liste avant de l'ajouter. De plus, il n'a pas besoin d'importations.

Richard Fredlund
la source
3
Cela a une complexité temporelle de O (n ^ 2) . Les réponses avec setet OrderedDictpeuvent avoir une complexité de temps amorti inférieure.
blubberdiblub
J'ai utilisé dans mon code cette solution et j'ai très bien fonctionné, mais je pense que cela prend du temps
Gerasimos Ragavanis
@blubberdiblub pouvez-vous expliquer quel mécanisme plus efficace de code existe dans set et OrderedDict qui pourrait les réduire en temps? (hors frais généraux de chargement)
ilias iliadis
@iliasiliadis Les implémentations habituelles de set et dict utilisent des hachages ou (une forme d'arbre équilibré). Vous devez envisager de créer l' ensemble ou le dict et de le rechercher (plusieurs fois), mais leur complexité amortie est généralement toujours inférieure à O (n ^ 2) . «Amorti» en termes simples signifie en moyenne (ils peuvent avoir les pires cas avec une complexité plus élevée que le cas moyen). Cela n'est pertinent que lorsque vous avez un grand nombre d'articles.
blubberdiblub
25

Un collègue m'a envoyé la réponse acceptée dans le cadre de son code pour une révision du code aujourd'hui. Bien que j'admire certainement l'élégance de la réponse en question, je ne suis pas satisfait de la performance. J'ai essayé cette solution (j'utilise set pour réduire le temps de recherche)

def ordered_set(in_list):
    out_list = []
    added = set()
    for val in in_list:
        if not val in added:
            out_list.append(val)
            added.add(val)
    return out_list

Pour comparer l'efficacité, j'ai utilisé un échantillon aléatoire de 100 entiers - 62 étaient uniques

from random import randint
x = [randint(0,100) for _ in xrange(100)]

In [131]: len(set(x))
Out[131]: 62

Voici les résultats des mesures

In [129]: %timeit list(OrderedDict.fromkeys(x))
10000 loops, best of 3: 86.4 us per loop

In [130]: %timeit ordered_set(x)
100000 loops, best of 3: 15.1 us per loop

Eh bien, que se passe-t-il si l'ensemble est supprimé de la solution?

def ordered_set(inlist):
    out_list = []
    for val in inlist:
        if not val in out_list:
            out_list.append(val)
    return out_list

Le résultat n'est pas aussi mauvais qu'avec le OrderedDict , mais toujours plus de 3 fois la solution d'origine

In [136]: %timeit ordered_set(x)
10000 loops, best of 3: 52.6 us per loop
volcan
la source
Agréable en utilisant la recherche rapide définie pour accélérer la comparaison en boucle. Si l'ordre n'a pas d'importance, la liste (set (x)) est encore 6x plus rapide que cela
Joop
@Joop, c'était ma première question pour mon collègue - l'ordre est important; sinon, cela aurait été un problème trivial
volcan
version optimisée de l'ensemble ordonné, pour toute personne intéressée def unique(iterable)::; seen = set(); seen_add = seen.add; return [item for item in iterable if not item in seen and not seen_add(item)]
DrD
25

Il existe également des solutions utilisant Pandas et Numpy. Ils renvoient tous les deux un tableau numpy, vous devez donc utiliser la fonction .tolist()si vous voulez une liste.

t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']

Solution Pandas

Utilisation de la fonction Pandas unique():

import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']

Solution Numpy

Utilisation de la fonction numpy unique().

import numpy as np
np.unique(t).tolist()
>>>['a','b','c']
np.unique(t2).tolist()
>>>['a','b','c']

Notez que numpy.unique () trie également les valeurs . La liste t2est donc retournée triée. Si vous souhaitez que l'ordre soit préservé, utilisez comme dans cette réponse :

_, idx = np.unique(t2, return_index=True)
t2[np.sort(idx)].tolist()
>>>['c','b','a']

La solution n'est pas aussi élégante par rapport aux autres, cependant, par rapport à pandas.unique (), numpy.unique () vous permet également de vérifier si les tableaux imbriqués sont uniques le long d'un axe sélectionné.

GM
la source
Cela convertira la liste en tableau numpy qui est un gâchis et ne fonctionnera pas pour les chaînes.
user227666
1
@ user227666 merci pour votre avis, mais ce n'est pas vrai, cela fonctionne même avec une chaîne et vous pouvez ajouter .tolist si vous voulez obtenir une liste ...
GM
1
Je pense que c'est un peu comme essayer de tuer une abeille avec un marteau. Fonctionne, bien sûr! Mais, importer une bibliothèque à cette fin peut être un peu exagéré, non?
Debosmit Ray
@DebosmitRay, cela peut être utile si vous travaillez dans la science des données où vous travaillez généralement avec numpy et plusieurs fois vous devez travailler avec numpy array.
GM
la meilleure réponse en 2020 @ DebosmitRay j'espère que vous changez d'avis et utilisez numpy / pandas chaque fois que vous le pouvez
Egos
21

Une autre façon de faire:

>>> seq = [1,2,3,'a', 'a', 1,2]
>> dict.fromkeys(seq).keys()
['a', 1, 2, 3]
James Sapam
la source
1
Notez que dans les versions Python modernes (2.7+ je pense, mais je ne m'en souviens pas avec certitude), keys()retourne un objet de vue de dictionnaire, pas une liste.
Dustin Wyatt
16

Simple et facile:

myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanlist = []
[cleanlist.append(x) for x in myList if x not in cleanlist]

Production:

>>> cleanlist 
[1, 2, 3, 5, 6, 7, 8]
Nima Soroush
la source
5
complexité quadratique néanmoins - inest une opération O (n) et vous cleanlistaurez au plus des nnombres => pire des cas ~ O (n ^ 2)
jermenkoo
6
la compréhension des listes ne doit pas être utilisée pour les effets secondaires.
Jean-François Fabre
13

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

entrez la description de l'image ici (Zoomé) entrez la description de l'image ici

Hashables commandés

entrez la description de l'image ici (Zoomé) entrez la description de l'image ici

Unhashables commandés

entrez la description de l'image ici (Zoomé) entrez la description de l'image ici

Corman
la source
11

J'avais un dict dans ma liste, donc je ne pouvais pas utiliser l'approche ci-dessus. J'ai eu l'erreur:

TypeError: unhashable type:

Donc, si vous vous souciez de la commande et / ou que certains articles ne sont pas lavables . Ensuite, vous pourriez trouver cela utile:

def make_unique(original_list):
    unique_list = []
    [unique_list.append(obj) for obj in original_list if obj not in unique_list]
    return unique_list

Certains peuvent considérer que la compréhension de la liste avec un effet secondaire n'est pas une bonne solution. Voici une alternative:

def make_unique(original_list):
    unique_list = []
    map(lambda x: unique_list.append(x) if (x not in unique_list) else False, original_list)
    return unique_list
cchristelis
la source
6
mapavec un effet secondaire est encore plus trompeur qu'un listcomp avec un effet secondaire. En outre, lambda x: unique_list.append(x)c'est juste un moyen plus maladroit et plus lent de passer unique_list.append.
abarnert
Un moyen très utile pour ajouter des éléments sur une seule ligne, merci!
ZLNK
2
@ZLNK s'il vous plaît, ne l'utilisez jamais. En plus d'être laid sur le plan conceptuel, il est également extrêmement inefficace, car vous créez en fait une liste potentiellement grande et la jetez juste pour effectuer une itération de base.
Eli Korvigo
10

Toutes les approches préservant l'ordre que j'ai vues jusqu'ici utilisent soit une comparaison naïve (avec O (n ^ 2) complexité temporelle au mieux) ou des combinaisons lourdes OrderedDicts/ set+ listqui sont limitées aux entrées lavables. Voici une solution O (nlogn) indépendante du hachage:

La mise à jour a ajouté l' keyargument, la documentation et la compatibilité Python 3.

# from functools import reduce <-- add this import on Python 3

def uniq(iterable, key=lambda x: x):
    """
    Remove duplicates from an iterable. Preserves order. 
    :type iterable: Iterable[Ord => A]
    :param iterable: an iterable of objects of any orderable type
    :type key: Callable[A] -> (Ord => B)
    :param key: optional argument; by default an item (A) is discarded 
    if another item (B), such that A == B, has already been encountered and taken. 
    If you provide a key, this condition changes to key(A) == key(B); the callable 
    must return orderable objects.
    """
    # Enumerate the list to restore order lately; reduce the sorted list; restore order
    def append_unique(acc, item):
        return acc if key(acc[-1][1]) == key(item[1]) else acc.append(item) or acc 
    srt_enum = sorted(enumerate(iterable), key=lambda item: key(item[1]))
    return [item[1] for item in sorted(reduce(append_unique, srt_enum, [srt_enum[0]]))] 
Eli Korvigo
la source
Pourtant, cette solution nécessite des éléments commandables. Je vais l'utiliser unifier ma liste de listes: c'est pénible de les lister tuple()et de les hacher. | | | | - D'une manière générale, le processus de hachage prend un temps proportionnel à la taille de l'ensemble des données, tandis que cette solution prend un temps O (nlog (n)), dépendant uniquement de la longueur de la liste.
loxaxs
Je pense que l'approche basée sur les ensembles est tout aussi bon marché (O (n log n)), ou moins cher, que le tri + la détection des uniques. (Cette approche se paralléliserait cependant beaucoup mieux.) Elle ne préserve pas non plus exactement l'ordre initial, mais elle donne un ordre prévisible.
9000
@ 9000 C'est vrai. Je n'ai jamais mentionné la complexité temporelle d'une approche basée sur une table de hachage, qui est évidemment O (n). Vous trouverez ici de nombreuses réponses intégrant des tables de hachage. Ils ne sont cependant pas universels, car ils nécessitent que les objets soient lavables. De plus, ils consomment beaucoup plus de mémoire.
Eli Korvigo
Prend du temps pour lire et comprendre cette réponse. Est-il utile d'énumérer lorsque vous n'utilisez pas les indices? Le reduce() travaille déjà sur une collection triée srt_enum, pourquoi avez-vous postulé à sortednouveau?
Brayoni
@Brayoni le premier tri est là pour regrouper des valeurs égales, le second tri est là pour restaurer l'ordre initial. L'énumération est nécessaire pour garder une trace de l'ordre relatif d'origine.
Eli Korvigo,
9

Si vous souhaitez conserver l'ordre et ne pas utiliser de modules externes, voici un moyen simple de le faire:

>>> t = [1, 9, 2, 3, 4, 5, 3, 6, 7, 5, 8, 9]
>>> list(dict.fromkeys(t))
[1, 9, 2, 3, 4, 5, 6, 7, 8]

Remarque: Cette méthode préserve l'ordre d'apparition, donc, comme indiqué ci-dessus, neuf viendront après un car c'était la première fois qu'elle apparaissait. Cependant, c'est le même résultat que vous obtiendriez en faisant

from collections import OrderedDict
ulist=list(OrderedDict.fromkeys(l))

mais il est beaucoup plus court et tourne plus vite.

Cela fonctionne car chaque fois que la fromkeysfonction essaie de créer une nouvelle clé, si la valeur existe déjà, elle la remplace simplement. Cependant, cela n'affectera pas du tout le dictionnaire, car fromkeyscrée un dictionnaire où toutes les clés ont la valeur None, donc il élimine efficacement tous les doublons de cette façon.

HEEL_caT666
la source
Essayez aussi ici
vineeshvs
8

Vous pouvez également faire ceci:

>>> t = [1, 2, 3, 3, 2, 4, 5, 6]
>>> s = [x for i, x in enumerate(t) if i == t.index(x)]
>>> s
[1, 2, 3, 4, 5, 6]

La raison pour laquelle cela fonctionne est que cette indexméthode ne renvoie que le premier index d'un élément. Les éléments en double ont des indices plus élevés. Reportez-vous ici :

list.index (x [, start [, end]])
Retourne un index de base zéro dans la liste du premier élément dont la valeur est x. Déclenche une ValueError s'il n'y a pas un tel élément.

Atonal
la source
C'est horriblement inefficace. list.indexest une opération en temps linéaire, ce qui rend votre solution quadratique.
Eli Korvigo
Tu as raison. Mais je pense aussi qu'il est assez évident que la solution est destinée à être un revêtement qui préserve l'ordre. Tout le reste est déjà là.
Atonal
7

Essayez d'utiliser des ensembles:

import sets
t = sets.Set(['a', 'b', 'c', 'd'])
t1 = sets.Set(['a', 'b', 'c'])

print t | t1
print t - t1
Charlie Martin
la source
7

Réduisez la variante en conservant la commande:

Supposons que nous ayons une liste:

l = [5, 6, 6, 1, 1, 2, 2, 3, 4]

Réduire la variante (inefficace):

>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]

5 fois plus rapide mais plus sophistiqué

>>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
[5, 6, 1, 2, 3, 4]

Explication:

default = (list(), set())
# user list to keep order
# use set to make lookup faster

def reducer(result, item):
    if item not in result[1]:
        result[0].append(item)
        result[1].add(item)
    return result

reduce(reducer, l, default)[0]
Sergey M Nikitin
la source
7

La meilleure approche pour supprimer les doublons d'une liste est d'utiliser la fonction set () , disponible en python, convertissant à nouveau cet ensemble en liste

In [2]: some_list = ['a','a','v','v','v','c','c','d']
In [3]: list(set(some_list))
Out[3]: ['a', 'c', 'd', 'v']
Anurag Misra
la source
@MeetZaveri heureux.!
Anurag Misra
L'instanciation de nouvelles listes et ensembles n'est pas gratuite. Que se passe-t-il si nous faisons cela plusieurs fois de suite rapidement (c'est-à-dire dans une boucle très serrée) et que les listes sont très petites?
Z4-tier
6

Vous pouvez utiliser la fonction suivante:

def rem_dupes(dup_list): 
    yooneeks = [] 
    for elem in dup_list: 
        if elem not in yooneeks: 
            yooneeks.append(elem) 
    return yooneeks

Exemple :

my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']

Usage:

rem_dupes(my_list)

['ceci', 'est', 'un', 'liste', 'avec', 'duplique', 'dans', 'le']

Cybernétique
la source
5

Il existe de nombreuses autres réponses suggérant différentes façons de le faire, mais ce sont toutes des opérations par lots, et certaines d'entre elles jettent la commande d'origine. Cela peut convenir selon ce dont vous avez besoin, mais si vous souhaitez parcourir les valeurs dans l'ordre de la première instance de chaque valeur et que vous souhaitez supprimer les doublons à la volée par rapport à tous à la fois, vous pouvez utiliser ce générateur:

def uniqify(iterable):
    seen = set()
    for item in iterable:
        if item not in seen:
            seen.add(item)
            yield item

Cela renvoie un générateur / itérateur, vous pouvez donc l'utiliser n'importe où que vous pouvez utiliser un itérateur.

for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
    print(unique_item, end=' ')

print()

Production:

1 2 3 4 5 6 7 8

Si vous en voulez un list, vous pouvez le faire:

unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))

print(unique_list)

Production:

[1, 2, 3, 4, 5, 6, 7, 8]
Cyphase
la source
seen = set(iterable); for item in seen: yield itemest presque certainement plus rapide. (Je n'ai pas essayé ce cas spécifique, mais ce serait ma supposition.)
dylnmc
2
@dylnmc, c'est une opération par lots, et elle perd également la commande. Ma réponse était spécifiquement destinée à être à la volée et par ordre de première occurrence. :)
Cyphase
5

Sans utiliser l'ensemble

data=[1, 2, 3, 1, 2, 5, 6, 7, 8]
uni_data=[]
for dat in data:
    if dat not in uni_data:
        uni_data.append(dat)

print(uni_data) 
Suresh Gupta
la source
5

Vous pouvez utiliser setpour supprimer les doublons:

mylist = list(set(mylist))

Mais notez que les résultats ne seront pas ordonnés. Si c'est un problème:

mylist.sort()
Flavio Wuensche
la source
1
Vous pouvez simplement faire: mylist = sorted (list (set (mylist)))
Erik Campobadal
5

Une meilleure approche pourrait être,

import pandas as pd

myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanList = pd.Series(myList).drop_duplicates().tolist()
print(cleanList)

#> [1, 2, 3, 5, 6, 7, 8]

et l'ordre reste préservé.

Akarsh Jain
la source
Bien que cela puisse bien fonctionner, l'utilisation d'une bibliothèque lourde comme des pandas à cet effet semble être une exagération.
Glutexo
4

Celui-ci se soucie de la commande sans trop de tracas (OrderdDict & autres). Probablement pas le moyen le plus Pythonique, ni le plus court, mais fait l'affaire:

def remove_duplicates(list):
    ''' Removes duplicate items from a list '''
    singles_list = []
    for element in list:
        if element not in singles_list:
            singles_list.append(element)
    return singles_list
cgf
la source
1. Vous ne devez jamais masquer les noms intégrés (au moins, aussi importants que list); 2. Votre méthode est extrêmement mauvaise: elle est quadratique en nombre d'éléments list.
Eli Korvigo
1. Exact, mais c'était un exemple; 2. C'est exact, et c'est exactement la raison pour laquelle je l'ai proposé. Toutes les solutions affichées ici ont des avantages et des inconvénients. Certains sacrifient la simplicité ou l'ordre, le mien sacrifie l'évolutivité.
cgf
c'est un algorithme "Shlemiel le peintre" ...
Z4-tier
4

le code ci-dessous est simple pour supprimer les doublons dans la liste

def remove_duplicates(x):
    a = []
    for i in x:
        if i not in a:
            a.append(i)
    return a

print remove_duplicates([1,2,2,3,3,4])

il renvoie [1,2,3,4]

vinay hegde
la source
2
Si vous ne vous souciez pas de la commande, cela prend beaucoup plus de temps. list(set(..))(plus d'un million de passes) battra cette solution d'environ 10 secondes entières - alors que cette approche prend environ 12 secondes, list(set(..))ne prend qu'environ 2 secondes!
dylnmc
@dylnmc c'est aussi un doublon d'une réponse
Eli Korvigo
4

Voici la solution pythonique la plus rapide comparée à d'autres répertoriées dans les réponses.

L'utilisation des détails d'implémentation de l'évaluation des courts-circuits permet d'utiliser la compréhension de liste, ce qui est assez rapide. visited.add(item)renvoie toujours Nonecomme résultat, qui est évalué comme False, donc le côté droit deor serait toujours le résultat d'une telle expression.

Faites le temps vous-même

def deduplicate(sequence):
    visited = set()
    adder = visited.add  # get rid of qualification overhead
    out = [adder(item) or item for item in sequence if item not in visited]
    return out
thodnev
la source
4

Utilisation de l' ensemble :

a = [0,1,2,3,4,3,3,4]
a = list(set(a))
print a

En utilisant unique :

import numpy as np
a = [0,1,2,3,4,3,3,4]
a = np.unique(a).tolist()
print a
Nurul Akter Towhid
la source
4

Malheureusement. La plupart des réponses ici ne préservent pas l'ordre ou sont trop longues. Voici une réponse simple et préservant l'ordre.

s = [1,2,3,4,5,2,5,6,7,1,3,9,3,5]
x=[]

[x.append(i) for i in s if i not in x]
print(x)

Cela vous donnera x avec les doublons supprimés mais préservant l'ordre.

ste_kwr
la source
3

Manière très simple en Python 3:

>>> n = [1, 2, 3, 4, 1, 1]
>>> n
[1, 2, 3, 4, 1, 1]
>>> m = sorted(list(set(n)))
>>> m
[1, 2, 3, 4]
Wariored
la source
2
sorted(list(...))est redondant ( sortedconvertit déjà implicitement son argument en un nouveau list, le trie, puis renvoie le nouveau list, donc utiliser les deux signifie créer un temporaire inutile list). Utilisez uniquement listsi le résultat n'a pas besoin d'être trié, utilisez uniquement sortedsi le résultat doit être trié.
ShadowRanger
3

La magie de Python Type intégré

En python, il est très facile de traiter les cas compliqués comme celui-ci et uniquement par le type intégré de python.

Laissez-moi vous montrer comment faire!

Méthode 1: Cas général

La façon ( code 1 ligne ) de supprimer l'élément dupliqué dans la liste et de conserver l'ordre de tri

line = [1, 2, 3, 1, 2, 5, 6, 7, 8]
new_line = sorted(set(line), key=line.index) # remove duplicated element
print(new_line)

Vous obtiendrez le résultat

[1, 2, 3, 5, 6, 7, 8]

Méthode 2: cas spécial

TypeError: unhashable type: 'list'

Le cas particulier pour traiter les données non partageables ( codes à 3 lignes )

line=[['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']]

tuple_line = [tuple(pt) for pt in line] # convert list of list into list of tuple
tuple_new_line = sorted(set(tuple_line),key=tuple_line.index) # remove duplicated element
new_line = [list(t) for t in tuple_new_line] # convert list of tuple into list of list

print (new_line)

Vous obtiendrez le résultat:

[
  ['16.4966155686595', '-27.59776154691', '52.3786295521147'], 
  ['17.6508629295574', '-27.143305738671', '47.534955022564'], 
  ['18.8051102904552', '-26.688849930432', '42.6912804930134'], 
  ['19.5504702331098', '-26.205884452727', '37.7709192714727'], 
  ['20.2929416861422', '-25.722717575124', '32.8500163147157']
]

Parce que le tuple est lavable et vous pouvez facilement convertir des données entre la liste et le tuple

Milo Chen
la source