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

708

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

def remove_duplicates():
    t = ['a', 'b', 'c', 'd']
    t2 = ['a', 'c', 'd']
    for t in t2:
        t.append(t.remove())
    return t
  • 15
    Ваше описание говорит, что вы проверяете «список» на наличие дубликатов, но ваш код проверяет два списка.
  • 0
    Может кто-нибудь опубликовать ответ, используя петли. Я понимаю, что это было бы «не пифонично», но как новый студент Python это было бы действительно полезно.
Теги:
list
algorithm
duplicates
intersection

44 ответа

1146
Лучший ответ

Общий подход к получению уникальной коллекции элементов - использование 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]

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


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

  • 192
    Следует отметить, что это убивает первоначальный порядок.
  • 62
    Следует также отметить, что это не работает, если у вас есть диктанты в списке.
Показать ещё 4 комментария
338

В 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']
  • 9
    Я думаю, что это единственный способ держать вещи в порядке.
  • 18
    @HerberthAmaral: Это очень далеко от истины, см. Как удалить дубликаты из списка в Python при сохранении порядка?
Показать ещё 3 комментария
174

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

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

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

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

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

76
>>> 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]
  • 26
    Обратите внимание, что этот метод работает за O (n ^ 2) времени и поэтому очень медленно работает с большими списками.
  • 9
    Однако это прекрасно работает для не хэш-контента
Показать ещё 4 комментария
61

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

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

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

27

Чтобы создать новый список, сохраняющий порядок первых элементов дубликатов в 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]

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

  • 2
    Это имеет временную сложность O (n ^ 2) . Ответы с set и OrderedDict могут иметь меньшую сложность амортизированного времени.
  • 0
    Я использовал в своем коде это решение и отлично работал, но я думаю, что это отнимает много времени
Показать ещё 2 комментария
18

Коллега отправил принятый ответ в качестве части его кода ко мне для кодового просмотра сегодня. Хотя я, конечно, восхищаюсь элегантностью ответного вопроса, я не доволен выступлением. Я пробовал это решение (я использую 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
  • 0
    Приятно использовать быстрый поиск, чтобы ускорить зацикленное сравнение. Если порядок не имеет значения, список (set (x)) все еще в 6 раз быстрее, чем этот.
  • 0
    @ Joop, это был мой первый вопрос для моего коллеги - порядок имеет значение; иначе это был бы тривиальный вопрос
18

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

>>> seq = [1,2,3,'a', 'a', 1,2]
>> dict.fromkeys(seq).keys()
['a', 1, 2, 3]
  • 1
    Обратите внимание, что в современных версиях Python (я думаю, что 2.7+, но я точно не помню), keys() возвращает объект представления словаря, а не список.
14

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

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]
  • 3
    тем не менее, квадратичная сложность - in операции O (n) и ваш cleanlist будет иметь не более n чисел => в худшем случае ~ O (n ^ 2)
  • 2
    Понимание списка не должно использоваться для побочных эффектов.
14

Существуют также решения с использованием 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() позволяет также проверить, уникальны ли вложенные массивы вдоль одной выбранной оси.

  • 0
    Это преобразует список в массив numpy, который является беспорядком и не будет работать для строк.
  • 1
    @ user227666 спасибо за ваш отзыв, но это не так, он работает даже со строкой, и вы можете добавить .tolist, если хотите получить список ...
Показать ещё 2 комментария
10

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

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
  • 5
    map с побочным эффектом еще более обманчива, чем listcomp с побочным эффектом. Кроме того, lambda x: unique_list.append(x) - просто более медленный и более медленный способ передать unique_list.append .
  • 0
    Очень полезный способ добавлять элементы в одну строку, спасибо!
Показать ещё 1 комментарий
7

Все подходы, 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]]))] 
  • 0
    Тем не менее, это решение требует элементов, которые можно заказать. Я буду использовать его для унификации моего списка списков: это неудобно для tuple() списков и их хэширования. | | | | - Вообще говоря, процесс хеширования занимает время, пропорциональное размеру целых данных, в то время как это решение занимает время O (nlog (n)), зависящее только от длины списка.
  • 0
    Я думаю, что подход на основе множеств одинаково дешев (O (n log n)) или дешевле, чем сортировка + обнаружение уникальных объектов. (Однако этот подход распараллелил бы намного лучше.) Он также не совсем сохраняет первоначальный порядок, но дает предсказуемый порядок.
Показать ещё 3 комментария
6

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

>>> 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, если нет такой пункт.

  • 0
    Это ужасно неэффективно. list.index - это операция с линейным временем, делающая ваше решение квадратичным.
  • 0
    Ты прав. Но также я полагаю, что вполне очевидно, что решение предназначено, чтобы быть одним лайнером, который сохраняет порядок. Все остальное уже здесь.
6

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

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

print t | t1
print t - t1
5

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

Лучший способ удаления дубликатов из списка - использовать функцию 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']
  • 0
    Работает без нареканий!
  • 0
    @MeetZaveri счастлив.
4

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

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]
  • 0
    seen = set(iterable); for item in seen: yield item почти наверняка быстрее. (Я не пробовал этот конкретный случай, но это было бы мое предположение.)
  • 2
    @dylnmc, это пакетная операция, и она также теряет порядок. Мой ответ был специально предназначен, чтобы быть на лету и в порядке первого появления. :)
4

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

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]

  • 2
    Если вы не заботитесь о порядке, то это занимает значительно больше времени. list(set(..)) (более 1 миллиона проходов) побьет это решение примерно на 10 полных секунд - тогда как этот подход занимает около 12 секунд, list(set(..)) занимает всего около 2 секунд!
  • 0
    @dylnmc это также дубликат значительно более старого ответа
4

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

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

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

Этот человек заботится о заказе без особых хлопот (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
  • 0
    1. Вы никогда не должны скрывать встроенные имена (по крайней мере, так же важно, как list ); 2. Ваш метод очень плохо масштабируется: он квадратичен по количеству элементов в list .
  • 0
    1. Верно, но это был пример; 2. Правильно, и именно поэтому я и предложил это. Все решения, размещенные здесь, имеют свои плюсы и минусы. Некоторые жертвуют простотой или порядком, мои жертвуют масштабируемостью.
3

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

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]

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

  • 0
    Хотя это может сработать, использование тяжелой библиотеки, такой как pandas, для этой цели кажется излишним.
3

Очень простой способ в 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]
  • 1
    sorted(list(...)) является избыточным ( sorted уже неявно преобразует свой аргумент в новый list , сортирует его, затем возвращает новый list , поэтому использование обоих способов означает создание ненужного временного list ). Используйте только list если результат не нужно сортировать, используйте только sorted если результат должен быть отсортирован.
  • 0
    Да, ты прав!
3

Использование 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
3

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

Использование деталей реализации оценки короткого замыкания позволяет использовать понимание списка, которое достаточно быстро. 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
2

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

mylist = list(set(mylist))

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

mylist.sort()
  • 0
    Вы можете просто сделать: mylist = sorted (list (set (mylist)))
2

Я думаю, что преобразование в набор - это самый простой способ удалить дубликат:

list1 = [1,2,1]
list1 = list(set(list1))
print list1
2

Отметьте это, если вы хотите удалить дубликаты (вместо редактирования нового списка) вместо использования встроенного набора, 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]
  • 0
    Используйте enumerate() чтобы получить индекс быстрее: for i, value in enumerate(t): if value in t[i + 1:]: t.remove(value)
  • 0
    не будет работать, если 3 значения одинаковы - например, [1,1,1]
2

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

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

В настоящее время вы можете использовать класс 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])
1

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

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

1

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

>>> lst = [1, 3, 4, 2, 1, 21, 1, 32, 21, 1, 6, 5, 7, 8, 2]
>>>
>>> dict_enum = {item:index for index, item in enumerate(lst)}
>>> print dict_enum.keys()
[32, 1, 2, 3, 4, 5, 6, 7, 8, 21]
  • 0
    Зачем вычислять / хранить индекс, если вы никогда не используете его? Это похоже на решение, предназначенное для сохранения порядка (путем сохранения последнего увиденного индекса каждого значения), которое забыло это сделать. list(set(lst)) достиг бы того же логического результата.
1

Здесь много ответов, в которых используется set(..) (который быстро задан для хэширования элементов) или список (который имеет недостаток, который приводит к алгоритму O (n 2).

Функция, которую я предлагаю, является гибридной: мы используем set(..) для элементов, которые являются хешируемыми, и list(..) для тех, которые не являются. Кроме того, он реализуется как генератор, так что мы можем, например, ограничить количество элементов или сделать некоторую дополнительную фильтрацию.

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

def uniq(iterable, key=lambda x: x):
    seens = set()
    seenl = []
    for item in iterable:
        k = key(item)
        try:
            seen = k in seens
        except TypeError:
            seen = k in seenl
        if not seen:
            yield item
            try:
                seens.add(k)
            except TypeError:
                seenl.append(k)

Теперь мы можем использовать это, например:

>>> list(uniq(["apple", "pear", "banana", "lemon"], len))
['apple', 'pear', 'banana']
>>> list(uniq(["apple", "pear", "lemon", "banana"], len))
['apple', 'pear', 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", [], "banana"], len))
['apple', 'pear', {}, 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", [], "banana"]))
['apple', 'pear', {}, 'lemon', [], 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", {}, "banana"]))
['apple', 'pear', {}, 'lemon', 'banana']

Это, таким образом, фильтр уникальности, который может работать на любом итерабельном и отфильтровывать uniques, независимо от того, являются ли они хешируемыми или нет.

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

  • 0
    Примечание: есть встроенные модули, которые нарушают предположение, изложенное в последнем абзаце; frozenset является хэшируемым, set - нет, и если они имеют одинаковые значения, они равны, но в этом коде они будут рассматриваться как неравные.
  • 0
    @ShadowRanger: да, я согласен с этим, как сказал, что это не решает всех проблем. Тем не менее, при использовании set(..) это просто не будет работать вообще, а при использовании list это приведет к линейному времени поиска. Таким образом, это подразумевается как «лучший» набор, но с некоторыми подводными камнями.
Показать ещё 1 комментарий
1

Если вы не заботитесь о порядке и хотите чего-то другого, чем предлагаемые выше питонические способы (то есть его можно использовать в интервью), то:

def remove_dup(arr):
    size = len(arr)
    j = 0    # To store index of next unique element
    for i in range(0, size-1):
        # If current element is not equal
        # to next element then store that
        # current element
        if(arr[i] != arr[i+1]):
            arr[j] = arr[i]
            j+=1

    arr[j] = arr[size-1] # Store the last element as whether it is unique or repeated, it hasn't stored previously

    return arr[0:j+1]

if __name__ == '__main__':
    arr = [10, 10, 1, 1, 1, 3, 3, 4, 5, 6, 7, 8, 8, 9]
    print(remove_dup(sorted(arr)))

Сложность времени: O (n)

Вспомогательное пространство: O (n)

Ссылка: http://www.geeksforgeeks.org/remove-duplicates-sorted-array/

1
def remove_duplicates(A):
   [A.pop(count) for count,elem in enumerate(A) if A.count(elem)!=1]
   return A

Компиляция списка для удаления дубликатов

1

Вы можете сделать это просто с помощью наборов.

Шаг1: Получить различные элементы списков
Шаг2 Получить общие элементы списков
Шаг 3 Объедините их

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

Чтобы удалить дубликаты, сделайте это SET, а затем снова создайте LIST и распечатайте/используйте его. У набора гарантировано наличие уникальных элементов. Например:

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

Выход будет выглядеть следующим образом (отмечено в 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!!
0

Иногда вам нужно удалить дубликаты на месте, не создавая новый список. Например, список большой или оставьте его как теневую копию

from collections import Counter
cntDict = Counter(t)
for item,cnt in cntDict.items():
    for _ in range(cnt-1):
        t.remove(item)
0

Python имеет множество встроенных функций. Вы можете использовать set(), чтобы удалить дубликаты из списка. Согласно вашему примеру ниже есть два списка t и t2

t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
result = list(set(t) - set(t2))
result

Ответ: ['b']

  • 0
    кто-то еще имеет аналогичный ответ
0

это просто читаемая функция, легко понятная, и я использовал структуру данных dict, я использовал несколько встроенных функций и улучшил сложность O (n)

def undup(dup_list):
    b={}
    for i in dup_list:
        b.update({i:1})
    return b.keys()
a=["a",'b','a']
print undup(a)

Отказ от ответственности: вы можете получить ошибку отступа (если скопировать и вставить), используйте приведенный выше код с правильным отступом перед вставкой

0

К несчастью. Большинство ответов здесь либо не сохраняют порядок, либо являются слишком длинными. Вот простой, сохраняющий порядок ответ.

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)

Это даст вам х с удаленными дубликатами, но с сохранением порядка.

0
list_with_unique_items = list(set(list_with_duplicates))
  • 0
    Здесь, кажется, есть довольно много других ответов. Что этот ответ предлагает по сравнению с другими опубликованными решениями? Кроме того, хотя этот код может ответить на вопрос, в нем нет объяснения. Пожалуйста, рассмотрите возможность добавления текста, чтобы объяснить, что он делает и почему отвечает на поставленный вопрос.
  • 0
    это тот, кто нуждается в объяснении. Некоторые любят / хотят / понимают ответы, которые похожи на эссе, другие - на ответы, использующие встроенную библиотеку python, некоторые - на ответы, которые не используют библиотеку python, но для тех, кто любит oneliners, не нуждается в объяснении.
0
def remove_duplicates(input_list):
  if input_list == []:
    return []
  #sort list from smallest to largest
  input_list=sorted(input_list)
  #initialize ouput list with first element of the       sorted input list
  output_list = [input_list[0]]
  for item in input_list:
    if item >output_list[-1]:
      output_list.append(item)
  return output_list   
  • 0
    Вместо того, чтобы поместить код строки таким образом, вы можете объяснить, что делает ваш код?
  • 0
    Чего вы не понимаете в этом Кодексе, разве вы не видите, что это для удаления дубликатов?
0

Для полноты, и поскольку это очень популярный вопрос, библиотека toolz предлагает unique:

>>> tuple(unique((1, 2, 3)))
(1, 2, 3)
>>> tuple(unique((1, 2, 1, 3)))
(1, 2, 3)
0

Для этого требуется установка стороннего модуля, но пакет iteration_utilities содержит функцию unique_everseen 1, которая может удалять все дубликаты при сохранении порядка:

>>> from iteration_utilities import unique_everseen

>>> list(unique_everseen(['a', 'b', 'c', 'd'] + ['a', 'c', 'd']))
['a', 'b', 'c', 'd']

Если вы хотите избежать накладных расходов на операцию добавления списка, вы можете вместо этого использовать itertools.chain:

>>> from itertools import chain
>>> list(unique_everseen(chain(['a', 'b', 'c', 'd'], ['a', 'c', 'd'])))
['a', 'b', 'c', 'd']

unique_everseen также работает, если в списках есть неумелые элементы (например, списки):

>>> from iteration_utilities import unique_everseen
>>> list(unique_everseen([['a'], ['b'], 'c', 'd'] + ['a', 'c', 'd']))
[['a'], ['b'], 'c', 'd', 'a']

Однако это будет (намного) медленнее, чем если элементы хешируются.


1 Раскрытие информации: Я являюсь автором iteration_utilities -library.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню