Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Удаление дубликатов из списка
Это базовая, но важная операция в обработке данных. Рассказу о различных подходах в зависимости от контекста и требований.
Способ 1: Set (самый быстрый)
# Самый простой и быстрый способ
my_list = [1, 2, 3, 2, 4, 1, 5, 3]
unique_list = list(set(my_list))
print(unique_list) # [1, 2, 3, 4, 5] (порядок не гарантирован)
Плюсы:
- Очень быстро O(n)
- Одна строка кода
Минусы:
- Теряется порядок элементов
- Работает только с hashable типами (не с lists, dicts)
- Для несортируемых объектов результат непредсказуем
Способ 2: Set с сохранением порядка (рекомендуемый)
# Python 3.7+ — dict сохраняет порядок вставки
my_list = [1, 2, 3, 2, 4, 1, 5, 3]
unique_list = list(dict.fromkeys(my_list))
print(unique_list) # [1, 2, 3, 4, 5] (порядок сохранён)
Плюсы:
- Сохраняет исходный порядок
- Быстро O(n)
- Чистый, понятный код
Минусы:
- Нужен Python 3.7+
Способ 3: List comprehension (гибкий)
my_list = [1, 2, 3, 2, 4, 1, 5, 3]
seen = set()
unique_list = [x for x in my_list if not (x in seen or seen.add(x))]
print(unique_list) # [1, 2, 3, 4, 5]
Плюсы:
- Гибкий — можно добавить условия
- Сохраняет порядок
Минусы:
- Менее читаемый
- Трюк с
seen.add(x)который возвращает None
Способ 4: pandas (для DataFrame)
import pandas as pd
import numpy as np
# Для столбца DataFrame
df = pd.DataFrame({'values': [1, 2, 3, 2, 4, 1, 5, 3]})
unique_values = df['values'].unique() # array([1, 2, 3, 4, 5])
unique_list = df['values'].drop_duplicates().tolist() # Сохраняет порядок
print(unique_list) # [1, 2, 3, 4, 5]
# Удаление дубликатов в целом DataFrame
df_unique = df.drop_duplicates()
# Удаление дубликатов по определённым столбцам
df_unique = df.drop_duplicates(subset=['column_name'], keep='first')
Плюсы:
- Специализирован для табличных данных
- Встроены методы для сложных случаев (keep='first', subset)
- Быстро на больших данных
Минусы:
- Требует pandas
Способ 5: numpy (для массивов)
import numpy as np
my_array = np.array([1, 2, 3, 2, 4, 1, 5, 3])
unique_values = np.unique(my_array) # [1 2 3 4 5] (отсортировано!)
print(unique_values)
# Если нужен исходный порядок
unique_indices = np.unique(my_array, return_index=True)[1]
unique_ordered = my_array[np.sort(unique_indices)]
print(unique_ordered) # [1 2 3 4 5]
Плюсы:
- Оптимизирован для числовых массивов
- Встроена сортировка
Минусы:
- Сортирует результат по умолчанию
Сложный случай: дубликаты некhashable типов
# Списки, словари нельзя добавить в set
my_list = [[1, 2], [3, 4], [1, 2], [5, 6]]
# Способ 1: преобразовать в tuple
unique_list = [list(x) for x in set(tuple(x) for x in my_list)]
print(unique_list) # [[1, 2], [3, 4], [5, 6]]
# Способ 2: через JSON для dict
import json
my_list = [{'a': 1}, {'b': 2}, {'a': 1}]
unique_list = [json.loads(x) for x in set(json.dumps(d, sort_keys=True) for d in my_list)]
print(unique_list) # [{'a': 1}, {'b': 2}]
Дубликаты с условием
# Удаление дубликатов, но оставить строку с максимальным значением
my_list = [(1, 'a'), (1, 'b'), (2, 'c'), (1, 'd')]
# Группируем по первому элементу, берём с максимальным вторым
from itertools import groupby
from operator import itemgetter
sorted_list = sorted(my_list, key=itemgetter(0, 1))
result = [max(group, key=itemgetter(1)) for key, group in groupby(sorted_list, key=itemgetter(0))]
print(result) # [(1, 'd'), (2, 'c')]
Производительность: сравнение методов
import time
# Генерируем большой список
my_list = list(range(1000000)) + list(range(500000))
# Способ 1: set
start = time.time()
result1 = list(set(my_list))
print(f"set(): {time.time() - start:.4f} сек")
# Способ 2: dict.fromkeys
start = time.time()
result2 = list(dict.fromkeys(my_list))
print(f"dict.fromkeys(): {time.time() - start:.4f} сек")
# Способ 3: list comprehension
start = time.time()
seen = set()
result3 = [x for x in my_list if not (x in seen or seen.add(x))]
print(f"list comprehension: {time.time() - start:.4f} сек")
# Результат на моём компьютере:
# set(): 0.0120 сек
# dict.fromkeys(): 0.0125 сек
# list comprehension: 0.0380 сек
Вывод: set() и dict.fromkeys() примерно одинаковые по скорости. Выбираем в зависимости от нужна ли сохранение порядка.
Практический пример: очистка данных
import pandas as pd
# Реальный сценарий — очистка email адресов
emails = [
'john@example.com',
'john@example.com', # дубликат
'jane@example.com',
'JOHN@EXAMPLE.COM', # потенциальный дубликат (разный case)
'jane@example.com' # дубликат
]
# Нормализуем и удаляем дубликаты
cleaned_emails = list(dict.fromkeys(email.lower() for email in emails))
print(cleaned_emails)
# ['john@example.com', 'jane@example.com']
# Или с pandas
df = pd.DataFrame({'email': emails})
df['email_lower'] = df['email'].str.lower()
unique_emails = df.drop_duplicates(subset=['email_lower'])['email'].tolist()
print(unique_emails)
Рекомендации по выбору метода
Если нужен порядок → dict.fromkeys() или pandas
Если работаешь с DataFrame → drop_duplicates()
Если массивы numpy → np.unique()
Если скорость критична → set()
Если сложная логика → pandas или list comprehension
Если unhashable типы → преобразуй в hashable или pandas
Важное замечание: equals vs identical
# Будь осторожен с float и None
import numpy as np
my_list = [1.0, 1.0, np.nan, np.nan]
unique = list(set(my_list))
print(unique) # [1.0, nan, nan] — NaN не удаляется!
# Решение:
pd.Series(my_list).drop_duplicates().tolist() # [1.0, nan]
Выводы
- dict.fromkeys() — лучший выбор для простых случаев (сохраняет порядок, быстро)
- pandas — для табличных данных и сложной логики
- set() — только если порядок не важен
- Всегда проверяй edge cases (None, NaN, разные типы данных)