Question Suppression des doublons dans les listes


À peu près, j'ai besoin d'écrire un programme pour vérifier si une liste a des doublons et si c'est le cas, il les supprime et renvoie une nouvelle liste avec les éléments qui ne sont pas 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

612
2017-11-01 00:45


origine


Réponses:


L'approche commune pour obtenir une collection unique d'éléments est d'utiliser un set. Les ensembles sont non ordonné collections de distinct objets. Pour créer un ensemble à partir de n'importe quel itérable, vous pouvez simplement le passer à l'intégré set() fonction. Si vous avez besoin ultérieurement d'une liste réelle, vous pouvez également transmettre l'ensemble à list() fonction.

L'exemple suivant devrait 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 à partir du résultat de l'exemple, l'ordre d'origine n'est pas conservé. Comme mentionné ci-dessus, les ensembles eux-mêmes sont des collections non ordonnées, donc l'ordre est perdu. Lors de la conversion d'un ensemble en liste, un ordre arbitraire est créé.

Si l'ordre est important pour vous, alors vous devrez utiliser un mécanisme différent. Une solution très courante pour cela est de compter sur OrderedDict pour garder l'ordre des clés pendant l'insertion:

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

Notez que cela a l'avantage de créer un dictionnaire en premier, puis de créer une liste à partir de celui-ci. Donc, si vous n'avez pas besoin de conserver la commande, il vaut mieux utiliser un ensemble. Check-out 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 le set aussi bien que OrderedDict solution nécessite que vos articles soient lavable. Cela signifie généralement qu'ils doivent être immuables. Si vous devez traiter des éléments qui ne sont pas traitables (par exemple des objets de liste), vous devrez utiliser une approche lente dans laquelle vous devrez essentiellement comparer chaque élément avec tous les autres éléments d'une boucle imbriquée.


1059
2017-11-01 00:49



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

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

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

En Python 3.6, la dict régulière devient à la fois ordonnée et compacte. (Cette fonctionnalité est valide 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 tout en conservant l'ordre:

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

En Python 3.7, la dict régulière est garantie à la fois ordonnée dans toutes les implémentations. Donc, la solution la plus courte et la plus rapide est:

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

300
2017-11-01 00:53



C'est un one-liner: list(set(source_list)) fera l'affaire.

UNE set est quelque chose qui ne peut pas avoir des doublons.

Mise à jour: une approche de préservation des commandes est deux lignes:

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

Ici, nous utilisons le fait que OrderedDict mémorise l'ordre d'insertion des clés et ne le modifie pas lorsqu'une valeur d'une clé particulière est mise à jour. Nous insérons True en tant que valeurs, mais nous pourrions insérer n'importe quoi, les valeurs ne sont tout simplement pas utilisées. (set travaille beaucoup comme un dictavec des valeurs ignorées, aussi.)


157
2017-11-01 00:49



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

66
2018-05-14 12:39



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

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

UNE set est garanti de ne pas avoir de doublons.


60
2017-11-01 00:49



Faire une nouvelle liste en conservant l'ordre des premiers éléments de doublons 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] puis newlist sera [1,2,3,4,5]

Cela vérifie que chaque nouvel élément n'apparaît pas dans la liste avant de l'ajouter. En outre, il n'a pas besoin d'importations.


28
2017-07-05 03:39



Une autre façon de faire:

>>> seq = [1,2,3,'a', 'a', 1,2]
>> dict.fromkeys(seq).keys()
['a', 1, 2, 3]

18
2018-01-01 15:39



Un collègue m'a envoyé la réponse acceptée dans le cadre de son code pour une codereview 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 ensemble 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 retiré 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 de la solution originale

In [136]: %timeit ordered_set(x)
10000 loops, best of 3: 52.6 us per loop

16
2017-09-17 09:52



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]

Sortie:

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

13
2018-04-14 23:33



Il existe également des solutions utilisant Pandas et Numpy. Ils renvoient tous les deux un tableau numpy donc vous devez 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 aussi les valeurs. Donc la liste t2 est retourné trié. Si vous voulez que la commande soit conservée, 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 si é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é.


12
2017-07-03 12:45