Удаление дубликатов в списках - PullRequest
814 голосов
/ 01 ноября 2011

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

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

Ответы [ 45 ]

11 голосов
/ 06 июня 2014

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

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
8 голосов
/ 13 января 2016

Все подходы к сохранению порядка, которые я видел здесь до сих пор, используют либо наивное сравнение (в лучшем случае с 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]]))] 
7 голосов
/ 06 июня 2017

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

>>> 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]])
Возврат нулевого индекса в спискепервого элемента, значение которого равно х.Вызывает ошибку ValueError, если такого элемента нет.

7 голосов
/ 01 ноября 2011

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

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

print t | t1
print t - t1
6 голосов
/ 23 октября 2018

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

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

6 голосов
/ 17 августа 2017

Лучший подход к удалению дубликатов из списка - использование функции 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']
6 голосов
/ 23 февраля 2019

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

>>> 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 создает словарь, в котором все ключи имеют значение None, поэтому эффективно удаляет все дубликаты таким образом.

6 голосов
/ 27 апреля 2015

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

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

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]
5 голосов
/ 12 октября 2017

Без использования набора

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 голосов
/ 26 августа 2015

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

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