Методы удаления дубликатов из списка в языке 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.

Удаление дубликатов из списка в Python - comments

En
без повторений python (python)