Python: устранение дубликатов в списке

Раздел: Основы Python -> Основы Python: списки

Удаление повторяющихся элементов из списка

Как эффективно удалить дубликаты с сохранением порядка элементов?

Наиболее эффективным способом в Python 3.7+ является использование dict.fromkeys(), поскольку словари сохраняют порядок вставки. Этот подход имеет линейную сложность O(n).

my_list = [3, 1, 2, 1, 4, 3, 5]
unique_list = list(dict.fromkeys(my_list))
print(unique_list)

задачи python 3 списки (задачи на списки в python 3)

[3, 1, 2, 4, 5]

Объяснение: dict.fromkeys() создает словарь, где ключи – элементы списка. Поскольку ключи уникальны, дубликаты отбрасываются. Преобразование обратно в список дает уникальные элементы в порядке их первого появления.

Типичная ошибка: попытка использовать множество set, если порядок важен. Set не гарантирует порядок. Также dict.fromkeys() работает только с хешируемыми элементами (числа, строки, кортежи и т.д.). Для списков внутри списка необходимо преобразовывать их в кортежи.

Как удалить дубликаты без сохранения исходного порядка?

Если порядок не имеет значения, оптимально использовать преобразование в множество.

my_list = [3, 1, 2, 1, 4, 3, 5]
unique_list = list(set(my_list))
print(unique_list)
[1, 2, 3, 4, 5]

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

Проблема: для нехешируемых элементов (например, вложенные списки) set не применим. Также нельзя полагаться на порядок.

Как удалить дубликаты вручную с помощью цикла?

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

my_list = [3, 1, 2, 1, 4, 3, 5]
unique = []
for item in my_list:
    if item not in unique:
        unique.append(item)
print(unique)
[3, 1, 2, 4, 5]

На каждой итерации проверяется наличие элемента в новом списке. Это простой, но неэффективный способ – квадратичная сложность O(n^2).

Основной недостаток – медленная работа на больших списках. Кроме того, операция in над списком тоже имеет линейную сложность.

Как использовать OrderedDict для гарантии порядка в старых версиях Python?

Для Python 3.6 и ранее, где словари не сохраняли порядок, применяется collections.OrderedDict.

from collections import OrderedDict
my_list = [3, 1, 2, 1, 4, 3, 5]
unique_list = list(OrderedDict.fromkeys(my_list))
print(unique_list)
[3, 1, 2, 4, 5]

OrderedDict сохраняет порядок вставки ключей. Этот метод работает в любых версиях Python 3.

На сегодняшний день (Python 3.7+) можно обойтись обычным dict, но OrderedDict остается явным и переносимым.

Дополнительные сценарии работы с уникальностью элементов

Удаление дубликатов из списка словарей по значению ключа

Допустим, имеется список словарей и требуется оставить только уникальные записи по полю 'id'. Для хешируемости словарь преобразуется в кортеж значений ключевого поля или используется промежуточное множество.

Пример
data = [{'id': 1, 'val': 'a'}, {'id': 2, 'val': 'b'}, {'id': 1, 'val': 'c'}]
seen = set()
unique_data = []
for d in data:
    key = d['id']
    if key not in seen:
        seen.add(key)
        unique_data.append(d)
print(unique_data)
[{'id': 1, 'val': 'a'}, {'id': 2, 'val': 'b'}]

Обратите внимание: сохраняется первое вхождение. Если нужно последнее, следует проходить список в обратном порядке.

Объединение двух списков без дубликатов

Часто требуется объединить два списка, исключив повторения. Сохранить порядок первого списка, а затем дополнить элементами второго, которых ещё нет.

Пример
list1 = [1, 2, 3]
list2 = [3, 4, 5]
unique_merged = list(dict.fromkeys(list1 + list2))
print(unique_merged)
[1, 2, 3, 4, 5]

dict.fromkeys() даёт порядок первого появления каждого элемента в объединённом списке.

Проверка наличия дубликатов с помощью set

Простая проверка: если длина списка равна длине множества, дубликатов нет.

Пример
def has_duplicates(lst):
    return len(lst) != len(set(lst))

print(has_duplicates([1, 2, 3]))
print(has_duplicates([1, 2, 2]))
False
True

Функция полезна для валидации входных данных.

Удаление дубликатов из вложенных списков (списков списков)

Вложенные списки нехешируемы, поэтому перед помещением в set их нужно превратить в кортежи.

Пример
nested = [[1, 2], [3, 4], [1, 2], [5, 6]]
unique_nested = list(set(tuple(sublist) for sublist in nested))
unique_nested = [list(t) for t in unique_nested]
print(unique_nested)
[[1, 2], [3, 4], [5, 6]]

Порядок элементов не гарантирован. Для сохранения порядка применяется dict.fromkeys с кортежами в качестве ключей.

Группировка элементов с подсчетом количества вхождений

Иногда нужно не удалять дубликаты, а подсчитать их количество. Для этого используется collections.Counter.

Пример
from collections import Counter

data = ['a', 'b', 'a', 'c', 'b', 'b']
counts = Counter(data)
print(counts)
Counter({'b': 3, 'a': 2, 'c': 1})

Counter возвращает словарь, где ключи – элементы, значения – число повторений. Можно получить список уникальных элементов через list(counts.keys()).

Фильтрация списка с сохранением уникальности по условию

Например, нужно оставить уникальные строки без учёта регистра. Приводим к нижнему регистру, а оригинал сохраняем только один раз.

Пример
words = ['Python', 'python', 'PYTHON', 'Java', 'java']
seen = set()
unique_words = []
for w in words:
    lower = w.lower()
    if lower not in seen:
        seen.add(lower)
        unique_words.append(w)
print(unique_words)
['Python', 'Java']

Сохраняется первое встреченное написание.

Задачи на списки в Python 3 - comments

En
задачи python 3 списки (python)