Удаление дубликатов в списках
в значительной степени мне нужно написать программу, чтобы проверить, есть ли в списке дубликаты, и если это так, он удаляет их и возвращает новый список с элементами, которые не были дублированы/удалены. Это то, что у меня есть, но честно говоря, я не знаю, что делать.
def remove_duplicates():
t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
for t in t2:
t.append(t.remove())
return t
30 ответов
В Python 2.7, новый способ удаления дубликатов из iterable при сохранении его в исходном порядке:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
В Python 3.5, OrderedDict имеет реализацию C. Мои тайминги показывают, что теперь это самый быстрый и самый короткий из различных подходов для Python 3.5.
В Python 3.6, регулярный дикт стал и упорядоченным и компактным. (Эта функция выполняется для CPython и PyPy, но не может в других реализациях). Что дает нам новый быстрый способ deduping при сохранении заказа:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
В Python 3.7, регулярный dict гарантируется как упорядоченным во всех реализациях. Итак, самое короткое и быстрое решение:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
это однострочный:list(set(source_list))
будет делать трюк.
A set
это то, что не может быть дубликатов.
Update: подход, сохраняющий порядок, состоит из двух строк:
from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()
здесь мы используем тот факт, что OrderedDict
запоминает порядок вставки ключей и не изменяет его при обновлении значения в определенном ключе. Вставляем True
как значения, но мы могли бы вставить что угодно, значения просто не используются. (set
работы как dict
с игнорированием значения.)
>>> 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]
Если вы не заботитесь о заказе, просто сделать это:
def remove_duplicates(l):
return list(set(l))
A set
гарантированно не имеет дубликатов.
чтобы создать новый список, сохраняя порядок первых элементов дубликатов в 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]
это проверяет каждый новый элемент не появился ранее в списке перед его добавлением. И не нуждается в импорте.
коллега отправил принятый ответ как часть своего кода мне для просмотра кода сегодня. Хотя я, конечно, восхищаюсь элегантностью ответа на вопрос, я не доволен выступлением. Я пробовал это решение (я использую 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
есть также решения с использованием панд и Numpy. Они оба возвращают массив numpy, поэтому вам нужно использовать функцию .tolist()
если вам нужен список.
t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']
решение панд
использование функции Pandas unique()
:
import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']
Numpy решение
использование функции 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']
решение не так элегантно по сравнению с другими, однако, по сравнению с пандами.unique (), numpy.unique () также позволяет проверить уникальность вложенных массивов вдоль одной выбранной оси.
легко и просто:
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]
Я имел dict в моем списке, поэтому я не мог использовать вышеуказанный подход. Я получил ошибку:
TypeError: unhashable type:
Так что если вы заботитесь о ордер и / или некоторые элементы unhashable. Тогда вы можете найти это полезным:
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
попробуйте использовать наборы:
import sets
t = sets.Set(['a', 'b', 'c', 'd'])
t1 = sets.Set(['a', 'b', 'c'])
print t | t1
print t - t1
вы также можете сделать это:
>>> 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
метод возвращает только первый индекс элемента. Повторяющиеся элементы имеют более высокие показатели. См.здесь:
список.index (x[, start[, end]])
Возвращает отсчитываемый от нуля индекс в списке первый элемент, значение которого равно x. Поднимает ValueError, если нет такой пункт.
все подходы, сохраняющие порядок, которые я видел здесь до сих пор, либо используют наивное сравнение (с O(N^2) временной сложностью в лучшем случае), либо тяжелый OrderedDicts
/set
+list
комбинации, которые ограничиваются hashable входов. Вот хэш-независимое решение 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]]))]
лучший подход к удалению дубликатов из списка-использование 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']
этот заботится о заказе без особых хлопот (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
уменьшить вариант с заказом сохранить:
предположим, что у нас есть список:
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 x быстрее, но более сложные
>>> 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]
ниже код прост для удаления дубликат в списке
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]
есть много других ответов, предлагающих разные способы сделать это, но все они являются пакетными операциями, и некоторые из них отбрасывают исходный заказ. Это может быть нормально в зависимости от того, что вам нужно, но если вы хотите перебирать значения в порядке первого экземпляра каждого значения, и вы хотите удалить дубликаты на лету против всех сразу, вы можете использовать этот генератор:
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]
без использования 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)
вот самое быстрое решение pythonic, приходящее к другим, перечисленным в ответах.
использование деталей реализации оценки короткого замыкания позволяет использовать понимание списка, которое достаточно быстро. 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
используя 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
очень простой способ в 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]
В настоящее время вы можете использовать Counter class:
>>> 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])
вот пример, возвращая список без repetiotions сохранение порядка. Не нуждается во внешнем импорте.
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
проверьте это, если вы хотите удалить дубликаты (на месте редактировать, а не возвращать новый список) без использования встроенного набора, dict.ключи, uniqify, счетчик
>>> 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]
Я думаю, что преобразование в set-самый простой способ удалить дубликат:
list1 = [1,2,1]
list1 = list(set(list1))
print list1
чтобы удалить дубликаты, сделайте его набором, а затем снова сделайте его списком и распечатайте/используйте его. Набор гарантированно имеет уникальные элементы. Например :
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!!
вы можете сделать это просто с помощью наборов.
Шаг 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'}
def remove_duplicates(A):
[A.pop(count) for count,elem in enumerate(A) if A.count(elem)!=1]
return A
список comprehesion для удаления дубликатов