Методы удаления дубликатов из списка в языке Python
Основные способы удаления дубликатов из списка в Python
Какой способ удаления дубликатов является наиболее эффективным и сохраняет порядок элементов?
Для списков, где все элементы хэшируемые, самым эффективным решением с сохранением исходного порядка является использование dict.fromkeys(). Начиная с Python 3.7 словари сохраняют порядок вставки. Пример:
lst = [3, 1, 2, 3, 2, 4, 1]
unique = list(dict.fromkeys(lst))
print(unique) # [3, 1, 2, 4]без повторений python (удаление дубликатов из списка в python)
[3, 1, 2, 4]
Проблема:
Метод не работает для нехэшируемых элементов (списки, словари, множества). В таких элементах возникает ошибка TypeError: unhashable type.
Решение:
Преобразовать нехэшируемые элементы в хэшируемые (например, кортежи для списков) или использовать цикл с проверкой равенства.
Как удалить дубликаты без сохранения порядка?
Самый простой способ – преобразовать список во множество, а затем обратно в список. Порядок элементов теряется.
lst = [3, 1, 2, 3, 2, 4, 1]
unique = list(set(lst))
print(unique) # [1, 2, 3, 4] (порядок не гарантирован)
[1, 2, 3, 4]
Проблема:
Не сохраняется порядок элементов. Если требуется исходная последовательность, set не подходит.
Как удалить дубликаты с помощью цикла и проверки вхождения?
Этот метод не требует хэшируемых элементов и сохраняет порядок. Создается пустой список, в который добавляются элементы, если их ещё нет.
lst = [3, 1, 2, 3, 2, 4, 1]
result = []
for x in lst:
if x not in result:
result.append(x)
print(result) # [3, 1, 2, 4]
[3, 1, 2, 4]
Проблема:
Для больших списков сложность O(n^2), что может быть медленно. Рекомендуется только для небольших данных.
Как использовать OrderedDict для сохранения порядка в старых версиях Python?
До Python 3.7 использовался collections.OrderedDict. Метод аналогичен dict.fromkeys.
from collections import OrderedDict
lst = [3, 1, 2, 3, 2, 4, 1]
unique = list(OrderedDict.fromkeys(lst))
print(unique) # [3, 1, 2, 4]
[3, 1, 2, 4]
Проблема:
OrderedDict немного медленнее dict.fromkeys и требует импорта.
Как удалить дубликаты из списка чисел с сортировкой?
Можно сначала отсортировать список, затем пройти по нему, удаляя повторы. Или использовать set и затем сортировать результат.
lst = [3, 1, 2, 3, 2, 4, 1]
unique = sorted(set(lst))
print(unique) # [1, 2, 3, 4]
[1, 2, 3, 4]
Проблема:
Сортировка занимает O(n log n), что может быть избыточно, если порядок не важен.
Как удалить дубликаты из списка списков (вложенные структуры)?
Списки нехэшируемы, поэтому преобразуем их в кортежи, затем используем dict.fromkeys.
lst = [[1,2], [1,2], [3,4], [3,4,5]]
# Преобразуем в кортежи
unique = [list(t) for t in dict.fromkeys(tuple(x) for x in lst)]
print(unique) # [[1,2], [3,4], [3,4,5]]
[[1,2], [3,4], [3,4,5]]
Проблема:
Если внутренние списки содержат нехэшируемые объекты, преобразование не сработает. Придется использовать глубокое сравнение.
Как удалить дубликаты с помощью библиотеки pandas?
Функция pd.unique() возвращает массив уникальных элементов в порядке появления.
import pandas as pd
lst = [3, 1, 2, 3, 2, 4, 1]
unique = pd.unique(lst).tolist()
print(unique) # [3, 1, 2, 4]
[3, 1, 2, 4]
Проблема:
Требуется установка pandas, что может быть избыточно для простой задачи.
Как удалить дубликаты с помощью numpy?
np.unique() возвращает отсортированные уникальные значения.
import numpy as np
lst = [3, 1, 2, 3, 2, 4, 1]
unique = np.unique(lst).tolist()
print(unique) # [1, 2, 3, 4]
[1, 2, 3, 4]
Проблема:
Не сохраняется порядок. Также требует установки numpy.
Расширенные примеры удаления дубликатов
Пример 1: удаление дубликатов с сохранением последнего вхождения
Если нужно сохранить последнее появление каждого дублирующегося элемента, можно перевернуть список, применить метод dict.fromkeys и снова перевернуть.
lst = [1, 2, 3, 1, 2, 4]
unique = list(dict.fromkeys(reversed(lst)))
unique.reverse()
print(unique) # [3, 1, 2, 4] (последние вхождения 1 и 2)
[3, 1, 2, 4]
Пример 2: удаление дубликатов из списка строк с игнорированием регистра
Для сравнения строк без учета регистра можно привести все к нижнему регистру, но при этом сохранить оригинальное написание первого вхождения. Используется dict.fromkeys с кортежем (нижний регистр, оригинал) и извлечение оригиналов.
lst = ['Apple', 'apple', 'Banana', 'banana', 'Apple']
unique = [orig for _, orig in dict.fromkeys((s.lower(), s) for s in lst)]
print(unique) # ['Apple', 'Banana']
['Apple', 'Banana']
Пример 3: удаление дубликатов из списка объектов по атрибуту
Для списка объектов с атрибутом id, удаление дубликатов на основе значения этого атрибута с сохранением порядка.
class Item:
def __init__(self, id, name):
self.id = id
self.name = name
def __repr__(self):
return f'Item({self.id},{self.name})'
lst = [Item(1,'A'), Item(2,'B'), Item(1,'C'), Item(3,'D'), Item(2,'E')]
seen = set()
unique = []
for x in lst:
if x.id not in seen:
seen.add(x.id)
unique.append(x)
print(unique) # [Item(1,A), Item(2,B), Item(3,D)]
[Item(1,A), Item(2,B), Item(3,D)]
Пример 4: удаление дубликатов из большого списка с использованием итератора
При обработке больших данных, которые не помещаются в память, можно использовать генератор и множество для проверки уникальности на лету.
def unique_generator(iterable):
seen = set()
for x in iterable:
if x not in seen:
seen.add(x)
yield x
lst = range(1000000) + range(500000) # искусственные дубликаты
unique = list(unique_generator(lst)) # результат 1000000 уникальных
print(len(unique)) # 1000000
1000000
Пример 5: удаление дубликатов из списка кортежей с вложенными изменяемыми объектами
Если кортеж содержит изменяемые элементы (списки), его хэш нестабилен. В таких случаях необходимо использовать глубокое преобразование в неизменяемую структуру, например, через repr или json.dumps.
import json
lst = [([1,2], 3), ([1,2], 3), ([3,4], 5)]
unique = []
seen = set()
for x in lst:
key = json.dumps(x, sort_keys=True)
if key not in seen:
seen.add(key)
unique.append(x)
print(unique) # [([1,2], 3), ([3,4], 5)]
[([1,2], 3), ([3,4], 5)]
Примечание:
Использование json.dumps может быть медленным для больших данных. Альтернативно, можно преобразовать в строку через repr.