Удаление дубликатов в списках

В значительной степени мне нужно написать программу, чтобы проверить, есть ли в списке дубликаты, и если он это делает, он удаляет их и возвращает новый список с элементами, которые не были дублированы/удалены. Это то, что у меня есть, но, если честно, я не знаю, что делать.

def remove_duplicates():
    t = ['a', 'b', 'c', 'd']
    t2 = ['a', 'c', 'd']
    for t in t2:
        t.append(t.remove())
    return t

Ответ 1

Обычный подход к получению уникальной коллекции предметов заключается в использовании set. Наборы являются неупорядоченными коллекциями различных объектов. Чтобы создать набор из любого итератора, вы можете просто передать его встроенной функции set(). Если позже вам снова понадобится реальный список, вы также можете передать набор в функцию list().

Следующий пример должен охватывать все, что вы пытаетесь сделать:

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

Как видно из примера, исходный порядок не поддерживается. Как упоминалось выше, сами наборы являются неупорядоченными коллекциями, поэтому порядок теряется. При преобразовании набора обратно в список создается произвольный порядок.

Поддержание порядка

Если порядок важен для вас, вам придется использовать другой механизм. Очень распространенным решением для этого является использование OrderedDict для сохранения порядка ключей во время вставки:

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

Начиная с Python 3.7, встроенный словарь гарантированно будет поддерживать порядок вставки, поэтому вы также можете использовать его напрямую, если вы используете Python 3.7 или более позднюю версию (или CPython 3.6):

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

Обратите внимание, что это требует дополнительных усилий для создания словаря, а затем создания списка из него. Если вам на самом деле не нужно сохранять порядок, лучше использовать набор. Ознакомьтесь с этим вопросом для получения дополнительной информации и альтернативных способов сохранить порядок при удалении дубликатов.


В заключение отметим, что как решения set, так и решения OrderedDict/dict требуют, чтобы ваши элементы были хэшируемыми. Обычно это означает, что они должны быть неизменными. Если вам приходится иметь дело с элементами, которые не могут быть хешируемыми (например, списочные объекты), то вам придется использовать медленный подход, при котором вам в основном придется сравнивать каждый элемент с каждым другим элементом во вложенном цикле.

Ответ 2

В Python 2.7 новый способ удаления дубликатов из итерации при сохранении в исходном порядке:

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

В Python 3.5 у OrderedDict есть реализация C. Мои тайминги показывают, что это теперь и самый быстрый и самый короткий из различных подходов для Python 3.5.

В Python 3.6 обычный dict стал как упорядоченным, так и компактным. (Эта функция выполняется для CPython и PyPy, но может отсутствовать в других реализациях). Это дает нам новый быстрый способ дедуплирования при сохранении порядка:

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

В Python 3.7 регулярный dict гарантирован как для всех, так и для всех реализаций. Итак, самое короткое и быстрое решение:

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

Ответ 3

Это однострочный: list(set(source_list)) выполнит трюк.

A set - это то, что не может иметь дубликатов.

Обновление: подход, сохраняющий порядок, состоит из двух строк:

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

Здесь мы используем тот факт, что OrderedDict запоминает порядок вставки ключей и не изменяет его при обновлении значения в определенном ключе. Мы вставляем True в качестве значений, но мы можем вставлять что угодно, значения просто не используются. (set работает так же, как и dict с игнорируемыми значениями.)

Ответ 4

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

Ответ 5

Если вы не заботитесь о заказе, просто выполните следующее:

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

A set гарантированно не имеет дубликатов.

Ответ 6

Чтобы создать новый список, сохраняющий порядок первых элементов дубликатов в L

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

например if L=[1, 2, 2, 3, 4, 2, 4, 3, 5], тогда newlist будет [1,2,3,4,5]

Это проверяет, что каждый новый элемент не появился ранее в списке перед его добавлением. Также им не нужны импорт.

Ответ 7

Коллега отправил принятый ответ в качестве части его кода ко мне для кодового просмотра сегодня. Хотя я, конечно, восхищаюсь элегантностью ответного вопроса, я не доволен выступлением. Я пробовал это решение (я использую set для уменьшения времени поиска)

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

Чтобы сравнить эффективность, я использовал случайную выборку из 100 целых чисел - 62 были уникальными

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

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

Ниже приведены результаты измерений

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

Хорошо, что произойдет, если set будет удален из решения?

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

Результат не так плох, как с OrderedDict, но еще более чем в 3 раза от исходного решения

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

Ответ 8

Другой способ:

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

Ответ 9

Существуют также решения с использованием Pandas и Numpy. Они возвращают массив numpy, поэтому вам нужно использовать функцию .tolist() если вам нужен список.

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

Решение Pandas

Использование функции Pandas unique():

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

Решения

Использование функции numpy unique().

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

Обратите внимание, что numpy.unique() также сортирует значения. Таким образом, список t2 будет отсортирован. Если вы хотите сохранить сохраненный порядок, как в этом ответе:

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

Решение не настолько элегантно по сравнению с другими, однако по сравнению с pandas.unique(), numpy.unique() позволяет также проверить, уникальны ли вложенные массивы вдоль одной выбранной оси.

Ответ 10

Простой и легкий:

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

Вывод:

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

Ответ 11

У меня был указатель в моем списке, поэтому я не мог использовать вышеупомянутый подход. Я получил ошибку:

TypeError: unhashable type:

Итак, если вам нужен порядок и/или некоторые элементы расчесываются. Тогда вы можете найти это полезным:

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

Некоторые могут рассмотреть понимание списка с побочным эффектом, чтобы не быть хорошим решением. Вот альтернатива:

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

Ответ 12

Все подходы, OrderedDicts порядок, которые я видел здесь, пока используют либо наивное сравнение (с наилучшей сложностью O (n ^ 2)), либо тяжелые команды OrderedDicts/set + list, которые ограничены входами хешируемого. Вот хеш-независимое решение O (nlogn):

Обновление добавило key аргумент, документацию и совместимость с 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]]))] 

Ответ 13

Попробуйте использовать наборы:

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

print t | t1
print t - t1

Ответ 14

Вы также можете сделать это:

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

Причина, по которой выше, заключается в том, что метод index возвращает только первый индекс элемента. Дублирующие элементы имеют более высокие индексы. См. здесь:

list.index(x [, start [, end]])
Возвращать индекс на основе нуля в списке первый элемент, значение которого равно x. Повышает значение ValueError, если нет такой пункт.

Ответ 15

Уменьшить вариант с сохранением порядка:

Предположим, что у нас есть список:

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

Уменьшить вариант (неэффективно):

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

5 быстрее, но сложнее

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

Пояснение:

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]

Ответ 16

Лучший способ удаления дубликатов из списка - использовать функцию set(), доступную в python, снова конвертируя этот в список

In [2]: some_list = ['a','a','v','v','v','c','c','d']
In [3]: list(set(some_list))
Out[3]: ['a', 'c', 'd', 'v']

Ответ 17

Вы можете использовать следующую функцию:

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

Пример:

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

Использование:

rem_dupes(my_list)

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

Ответ 18

Если вы хотите сохранить порядок и не использовать какие-либо внешние модули, вот простой способ сделать это:

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

Примечание. Этот метод сохраняет порядок появления, поэтому, как показано выше, девять будут приходить после одного, потому что это был первый раз, когда он появился. Это, однако, тот же результат, который вы получили бы при выполнении

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

но он намного короче и работает быстрее.

Это работает, потому что каждый раз, fromkeys функция fromkeys пытается создать новый ключ, если значение уже существует, оно просто перезаписывает его. Однако это никак не повлияет на словарь, поскольку fromkeys создает словарь, в котором все ключи имеют значение None, поэтому эффективно удаляет все дубликаты таким образом.

Ответ 19

Есть много других ответов, предлагающих разные способы сделать это, но они все пакетные операции, а некоторые из них выбрасывают исходный порядок. Это может быть в порядке, в зависимости от того, что вам нужно, но если вы хотите перебирать значения в порядке первого экземпляра каждого значения, и вы хотите удалить дубликаты "на лету" против всех одновременно, вы можете использовать этот генератор:

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

Это возвращает генератор/итератор, поэтому вы можете использовать его в любом месте, где вы можете использовать итератор.

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

print()

Вывод:

1 2 3 4 5 6 7 8

Если вам нужен list, вы можете сделать это:

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

print(unique_list)

Вывод:

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

Ответ 20

Без использования 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) 

Ответ 21

Этот человек заботится о заказе без особых хлопот (OrderdDict и другие). Вероятно, это не самый питоновский путь или кратчайший путь, но делает трюк:

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

Ответ 22

ниже код прост для удаления дубликата в списке

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

он возвращает [1,2,3,4]

Ответ 23

Использование set:

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

Использование уникальный:

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

Ответ 24

Еще один лучший подход может быть,

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]

и порядок остается сохраненным.

Ответ 25

Здесь самое быстрое питоновское решение, дружественное к другим, перечисленным в ответах.

Использование деталей реализации оценки короткого замыкания позволяет использовать понимание списка, которое достаточно быстро. visited.add(item) всегда возвращает None в результате, который оценивается как False, поэтому правая часть or всегда будет результатом такого выражения.

Время это самостоятельно

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

Ответ 26

Очень простой способ в 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]

Ответ 27

Вы можете использовать set для удаления дубликатов:

mylist = list(set(mylist))

Но обратите внимание, что результаты будут неупорядоченными. Если это проблема:

mylist.sort()

Ответ 28

В настоящее время вы можете использовать класс Counter:

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

Ответ 29

Вот пример, возвращающий список без сохранения порядка повторения. Не требуется никакого внешнего импорта.

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

Ответ 30

Отметьте это, если вы хотите удалить дубликаты (вместо редактирования нового списка) вместо использования встроенного набора, dict.keys, uniqify, counter

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