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 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
656
demandé sur Raymond Hettinger 2011-11-01 04:45:24

30 réponses

L'approche commune pour obtenir une collection unique d'objets est d'utiliser un set . Les ensembles sont unordered collections de objets distincts . Pour créer un ensemble à partir de n'importe quel itérable, vous pouvez simplement le passer à la fonction intégrée set() . Si vous avez besoin plus tard d'une liste réelle à nouveau, vous pouvez également passer l'ensemble à la fonction list() .

L'exemple suivant devrait couvrir 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, la commande d'origine ne l'est pas. Comme mentionné ci-dessus, les ensembles eux-mêmes sont des collections non ordonnées, de sorte que l'ordre est perdu. Lors de la conversion d'un retour à une liste, un ordre arbitraire est créé.

Si l'ordre est important pour vous, alors vous devrez utiliser un autre mécanisme. Une solution très commune pour cela est s'appuyer sur OrderedDict pour conserver l'ordre des touches lors de l'insertion:

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

notez qu'il s'agit de créer d'abord un dictionnaire, puis une liste à partir de celui-ci. Donc, si vous n'avez pas réellement besoin de préserver l'ordre, il est préférable d'utiliser un ensemble. Cochez cette question pour plus de détails et d'autres façons de préserver l'ordre lors de la suppression des doublons.


enfin, notez que tant la solution set que la solution OrderedDict exigent que vos articles soient hachable . Cela signifie généralement qu'ils ont d'être immuable. Si vous avez à traiter avec des éléments qui ne sont pas hachables (par exemple des objets list), alors vous devrez utiliser une approche lente dans laquelle vous devrez essentiellement comparer chaque élément avec chaque autre élément dans une boucle imbriquée.

1136
répondu poke 2018-01-31 20:25:25

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 , l'OrderedDict a une implémentation C. Mes timings 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 commandé 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 le plus rapide de deduping tout en conservant l'ordre:

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

en Python 3.7 , le dict régulier est garanti aux deux commandé à travers toutes les implémentations. ainsi, la solution la plus courte et la plus rapide est:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
307
répondu Raymond Hettinger 2017-12-22 08:26:41

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

A set est quelque chose qui ne peut pas avoir de doublons.

mise à Jour: une ordonnance de préservation de la démarche est de deux lignes:

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

ici nous utilisons le fait que OrderedDict se souvient de l'ordre d'insertion des clés, et ne le change pas quand une valeur à une clé particulière est mise à jour. Nous insérons True comme valeurs, mais nous pourrions insérer n'importe quoi, valeurs sont tout simplement pas utilisé. ( set fonctionne beaucoup comme un dict avec des valeurs ignorées, aussi.)

161
répondu 9000 2017-06-05 16:39:17
>>> 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]
69
répondu Neeraj 2013-05-14 12:39:55

si vous ne vous souciez pas de l'ordre, faites juste ceci:

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

Un set est la garantie de ne pas avoir de doublons.

63
répondu Brendan Long 2011-11-01 00:49:08

pour faire une nouvelle liste 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] puis newlist sera [1,2,3,4,5]

ceci vérifie que chaque nouvel élément n'est pas déjà apparu dans la liste avant de l'ajouter. Il n'a pas non plus besoin d'importations.

28
répondu Richard Fredlund 2014-08-27 23:14:19

une autre façon de faire:

>>> seq = [1,2,3,'a', 'a', 1,2]
>> dict.fromkeys(seq).keys()
['a', 1, 2, 3]
18
répondu James Sapam 2016-12-03 03:23:23

un collègue m'a envoyé aujourd'hui la réponse acceptée comme faisant partie de son code pour une entrevue. 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

que se passe-t-il si set 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 encore plus de 3 fois de la solution originale

In [136]: %timeit ordered_set(x)
10000 loops, best of 3: 52.6 us per loop
17
répondu volcano 2014-09-17 09:52:45

il y a aussi des solutions utilisant Pandas et Numpy. Ils reviennent 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']

Pandas solution

utilisant la fonction Pandas unique() :

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

Numpy solution

utilisant 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 . Ainsi la liste t2 est retournée triée. Si vous voulez 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 que les 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é.

14
répondu G M 2017-12-06 10:51:24

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
répondu Nima Soroush 2015-04-14 23:33:40

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

TypeError: unhashable type:

donc si vous vous souciez de commander et/ou certains articles sont unhashable . Alors 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
11
répondu cchristelis 2014-10-27 10:58:38

Essayez d'utiliser des jeux:

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

print t | t1
print t - t1
6
répondu Charlie Martin 2011-11-01 00:54:13

vous pourriez aussi 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 ci-dessus fonctionne est que la méthode index retourne seulement le premier index d'un élément. Les éléments dupliqués ont des indices plus élevés. Se référer à ici :

liste.indice (x [, début [, fin]])

Retour index à base zéro dans la liste de le premier article dont la valeur est X. Soulève une erreur de valeur si là n' un tel objet.

6
répondu Atonal 2017-06-06 09:12:26

toutes les approches de conservation des commandes que j'ai vu jusqu'ici soit utiliser la comparaison naïve (avec O (N^2) le temps-la complexité au mieux) ou lourd-poids OrderedDicts / set + list les combinaisons qui sont limitées aux entrées hachables. Voici une solution o(nlogn) indépendante du hachage:

Update a ajouté l'argument key , 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]]))] 
6
répondu Eli Korvigo 2018-02-12 14:59:10

la meilleure façon de supprimer les doublons d'une liste est d'utiliser la fonction set() , disponible en python, convertissant à nouveau ce set 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']
5
répondu Anurag Misra 2017-08-17 07:39:25

celui-ci se soucie de l'ordre sans trop de tracas (OrderdDict & autres). Probablement pas la voie la plus pythonique, ni la plus courte, mais fait le tour:

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
4
répondu cgf 2014-09-02 11:37:54

réduire la variante avec conserver la commande:

supposons que nous avons la 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 x 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]
4
répondu Sergey M Nikitin 2015-04-27 14:56:35

le code ci-dessous est simple pour supprimer le double 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]

4
répondu vinay hegde 2015-08-13 21:54:27

il y a beaucoup d'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 l'ordre original. Cela peut être correct en fonction de ce dont vous avez besoin, mais si vous voulez itérer au-dessus des valeurs dans l'ordre de la première instance de chaque valeur, et vous voulez supprimer les doublons à la volée versus tout à 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

renvoie un générateur / itérateur, vous pouvez donc l'utiliser partout où 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()

sortie:

1 2 3 4 5 6 7 8

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

sortie:

[1, 2, 3, 4, 5, 6, 7, 8]
4
répondu Cyphase 2015-08-25 23:51:57

sans utiliser " set

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) 
4
répondu Suresh Gupta 2017-10-12 10:28:17

Voici la solution pythonique la plus rapide pour les autres.

L'utilisation des détails de mise en œuvre de l'évaluation de court-circuit permet d'utiliser la compréhension de liste, qui est assez rapide. visited.add(item) renvoie toujours None , ce qui est évalué comme False , de sorte que le côté droit de or serait toujours le résultat d'une telle expression.

Temps-le 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
3
répondu thodnev 2017-04-01 19:56:01

utilisant set :

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

à l'Aide uniques :

import numpy as np
a = [0,1,2,3,4,3,3,4]
a = np.unique(a).tolist()
print a
3
répondu Nurul Akter Towhid 2017-07-29 00:39:14

façon 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]
3
répondu Wariored 2018-08-12 16:16:39

de nos jours, vous pouvez utiliser la classe de comptoir:

>>> import collections
>>> c = collections.Counter([1, 2, 3, 4, 5, 6, 1, 1, 1, 1])
>>> c.keys()
dict_keys([1, 2, 3, 4, 5, 6])
2
répondu jb. 2013-06-18 10:54:54

voici un exemple, Liste de retour sans répétitions préserver l'ordre. N'a pas besoin de ces importations.

def GetListWithoutRepetitions(loInput):
    # return list, consisting of elements of list/tuple loInput, without repetitions.
    # Example: GetListWithoutRepetitions([None,None,1,1,2,2,3,3,3])
    # Returns: [None, 1, 2, 3]

    if loInput==[]:
        return []

    loOutput = []

    if loInput[0] is None:
        oGroupElement=1
    else: # loInput[0]<>None
        oGroupElement=None

    for oElement in loInput:
        if oElement<>oGroupElement:
            loOutput.append(oElement)
            oGroupElement = oElement
    return loOutput
2
répondu Apogentus 2014-06-09 10:33:18

Cochez cette case si vous voulez supprimer les doublons (modifier en place plutôt que de retourner une nouvelle liste) sans utiliser Inbuilt set, dict.clés, uniqify, compteur

>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> for i in t:
...     if i in t[t.index(i)+1:]:
...         t.remove(i)
... 
>>> t
[3, 1, 2, 5, 6, 7, 8]
2
répondu user2404093 2015-11-20 15:20:40

je pense que la conversion en set est la façon la plus facile de supprimer dupliquer:

list1 = [1,2,1]
list1 = list(set(list1))
print list1
2
répondu 2017-07-29 00:33:01

pour supprimer les doublons, faites-en un ensemble et ensuite faites-en une liste et imprimez/utilisez-la. Un ensemble est garanti d'avoir des éléments uniques. Par exemple:

a = [1,2,3,4,5,9,11,15]
b = [4,5,6,7,8]
c=a+b
print c
print list(set(c)) #one line for getting unique elements of c

la sortie sera la suivante (cochée en python 2.7)

[1, 2, 3, 4, 5, 9, 11, 15, 4, 5, 6, 7, 8]  #simple list addition with duplicates
[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 15] #duplicates removed!!
1
répondu krozaine 2015-08-25 08:38:44

vous pouvez faire cela simplement en utilisant des ensembles.

etape n ° 1: Obtenir les Différents éléments des listes

Step2 Obtenir les éléments Communs des listes

Etape 3 Combiner

In [1]: a = ["apples", "bananas", "cucumbers"]

In [2]: b = ["pears", "apples", "watermelons"]

In [3]: set(a).symmetric_difference(b).union(set(a).intersection(b))
Out[3]: {'apples', 'bananas', 'cucumbers', 'pears', 'watermelons'}
1
répondu Anurag Misra 2017-08-18 11:11:54
def remove_duplicates(A):
   [A.pop(count) for count,elem in enumerate(A) if A.count(elem)!=1]
   return A

Une liste comprehesion de supprimer les doublons

1
répondu ᴡʜᴀᴄᴋᴀᴍᴀᴅᴏᴏᴅʟᴇ3000 2017-08-26 23:23:42