В основном мне нужно написать программу, которая проверяет, есть ли в списке дубликаты, и если есть, то удаляет их и возвращает новый список с элементами, которые не были продублированы/удалены. Вот что у меня есть, но, честно говоря, я не знаю, что делать.
def remove_duplicates():
t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
for t in t2:
t.append(t.remove())
return t
Обычный подход для получения уникальной коллекции элементов - это использование 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
требуют, чтобы ваши элементы были хэшируемыми. Обычно это означает, что они должны быть неизменяемыми. Если вы имеете дело с элементами, которые не являются хэшируемыми (например, объекты списка), то вам придется использовать медленный подход, при котором вам придется сравнивать каждый элемент с каждым другим элементом во вложенном цикле.
В 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']
Это односложно: list(set(source_list))
сделает трюк.
Набор" - это то, что не может иметь дубликатов.
Обновление: подход, сохраняющий порядок, состоит из двух строк:
from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()
Здесь мы используем тот факт, что OrderedDict
запоминает порядок вставки ключей и не меняет его, когда значение по определенному ключу обновляется. В качестве значений мы вставляем True
, но мы можем вставить что угодно, значения просто не используются. (set
тоже работает как dict
с игнорируемыми значениями).
Если вам не важен порядок, просто сделайте это:
def remove_duplicates(l):
return list(set(l))
В наборе
гарантированно нет дубликатов.
Чтобы сделать новый список с сохранением порядка элементов первого дубликатов в Л
newlist=[II для Н II в перечислить(L), если второй не в L [Н]]
например, `если я=[1, 2, 2, 3, 4, 2, 4, 3, 5]тогда
newlistбудет
[1,2,3,4,5]``
Это проверяет каждый новый элемент, ранее не появлялись в списке, прежде чем добавлять его. Также она не нуждается в импорте.
Коллега послал принято отвечать в рамках своего кода для меня на сегодня codereview. Хотя я конечно восхищаюсь элегантностью ответ на вопрос, я не доволен выступлением. Я пробовал это решение (я использую набор для сокращения времени поиска)
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
Ну, что произойдет, если удаляются из раствора?
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
Другой способ:
>>> seq = [1,2,3,'a', 'a', 1,2]
>> dict.fromkeys(seq).keys()
['a', 1, 2, 3]
Существуют также решения с использованием Панды и NumPy. Обе они возвращают массив NumPy, так что вы должны использовать функцию .список()
Если вы хотите получить список.
t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']
Решение ## панды
Используя функцию панды уникальные()
:
import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']
Решение # библиотеки numpy#
Используя функции библиотеки numpy уникальные()
.
import numpy as np
np.unique(t).tolist()
>>>['a','b','c']
np.unique(t2).tolist()
>>>['a','b','c']
Обратите внимание, что и NumPy.уникальный() также отсортировать значения. Поэтому список Т2
возвращает отсортированный. Если вы хотите, чтобы порядок сохранился использовать как в этот ответ:
_, idx = np.unique(t2, return_index=True)
t2[np.sort(idx)].tolist()
>>>['c','b','a']
Решение не так элегантно по сравнению с другими, однако, по сравнению с пандами.уникальный(), и NumPy.уникальный() позволяет проверить, если вложенные массивы уникальны вдоль одной выбранной оси.
Простой и легкий:
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
Все заказ-сохранение подходов, которые я'вэ видел здесь до сих пор либо использовать наивные сравнения (с О(N^2) времени сложность в лучшем случае) или тяжелой-вес OrderedDicts
/установить
+список
комбинаций, которые ограничиваются hashable входов. Вот хэш-независимое решение за o(nlogn):
Обновление добавлена ключ
аргумент, документации и 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]]))]
Если вы хотите сохранить заказ, а не использовать здесь какие-либо внешние модули-это простой способ сделать это:
``питон
Т = [1, 9, 2, 3, 4, 5, 3, 6, 7, 5, 8, 9] Список(дикт.fromkeys(Т)) [1, 9, 2, 3, 4, 5, 6, 7, 8] ``
Примечание: этот метод сохраняет порядок внешний вид, так, как показано выше, девять придет после, потому что это был первый раз, когда он появился. Однако, такой же результат, как если бы вы с делали
питон из коллекции импорт OrderedDict ulist=список(OrderedDict.fromkeys(л))
но он гораздо короче и работает быстрее.
Это работает, потому что каждый раз, когда функция fromkeys
пытается создать новый ключ, если значение уже существует, он будет просто переписать его. Это не влияет на словарь на все однако, как fromkeys создает словарь, в котором все ключи имеют значение None
, поэтому эффективно устраняет все дубликаты в эту сторону.
Попробуйте использовать наборы:
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]
Причина того, что вышеуказанные работы заключается в том, что индекс
метод возвращает только первый индекс элемента. Повторяющиеся элементы имеют более высокие показатели. Смотрите здесь:
список.индекс(Х[, с[, конец]]) возврат нуля индекс в списке первый элемент, значение которого является X. Поднимает ValueError, если нет В такого пункта.
Уменьшить вариант с заказом сохранения:
Предположим, что мы имеем список:
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]
Вы можете использовать следующую функцию:
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)
['Это', 'Это', 'Это', 'лист#39;, 'с', 'dupicates', 'в', 'его']
Лучший подход удаление дубликатов из списка, используя комплект() функции, доступные в 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']
Есть много других ответов, предлагая различные способы для этого, но они'вновь все пакетные операции, и некоторым из них выбросить в первоначальном порядке. Что может быть хорошо в зависимости от того, что вам нужно, но если вы хотите, чтобы выполнить итерации по значениям в порядке первый экземпляр каждого значения, и вы хотите удалить дубликаты "на лету" по отношению ко всем сразу, ты можешь использовать этот генератор:
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
Если вы хотите "список", вы можете сделать это:
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]
Без использования комплекта
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)