Удаление дубликатов в списках
В значительной степени мне нужно написать программу, чтобы проверить, есть ли в списке дубликаты, и если он это делает, он удаляет их и возвращает новый список с элементами, которые не были дублированы/удалены. Это то, что у меня есть, но, если честно, я не знаю, что делать.
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]