Удаление дубликатов в Python: подробное руководство
Пять способов удаления дубликатов из списка Python: set, dict.fromkeys, цикл со множеством, списковое включение и Counter.
Дублирующиеся значения в списке Python встречаются повсеместно: при сборе пользовательского ввода, объединении наборов данных или чтении файлов. В этом руководстве рассматриваются пять практических способов удаления дубликатов — каждый с разным балансом между скоростью, сохранением порядка и читаемостью кода.
| Метод | Сохраняет порядок | Работает с нехэшируемыми элементами | Читаемость |
|---|---|---|---|
set() | Нет | Нет | Высокая |
dict.fromkeys() | Да (Python 3.7+) | Нет | Высокая |
| Цикл со множеством seen | Да | Нет | Средняя |
| Списковое включение | Да | Нет | Средняя |
Counter (поиск дубликатов) | Да | Нет | Высокая |
Использование set() для удаления дубликатов
Преобразование списка в множество — самый быстрый и лаконичный способ устранить дубликаты. Множество хранит только уникальные хэшируемые значения, поэтому все повторяющиеся элементы автоматически отбрасываются.
Вывод (порядок может отличаться):
[1, 2, 3, 4, 5]Когда использовать: порядок элементов не важен, и список содержит только хэшируемые элементы (числа, строки, кортежи).
Предупреждение: множества неупорядочены. Даже если небольшие множества целых чисел часто выводятся в отсортированном порядке, полагаться на это нельзя. Если порядок важен, используйте один из методов ниже.
Использование dict.fromkeys() для сохранения порядка
dict.fromkeys() создаёт словарь, ключами которого являются элементы списка. Поскольку ключи словаря уникальны и, начиная с Python 3.7, сохраняют порядок вставки, этот метод удаляет дубликаты, сохраняя исходный порядок.
Вывод:
[1, 2, 3, 4, 5]Это идиоматическая однострочная конструкция для дедупликации с сохранением порядка в современном Python (3.7+). Она также немного быстрее явного цикла, поскольку операции со словарём выполняются на уровне C.
Использование цикла for с множеством seen
Когда требуется полный контроль — например, чтобы логировать пропущенные дубликаты или применять пользовательскую логику сравнения, — явный цикл является наиболее понятным подходом.
def remove_duplicates(lst):
seen = set()
result = []
for item in lst:
if item not in seen:
seen.add(item)
result.append(item)
return result
my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
print(remove_duplicates(my_list))Вывод:
[3, 1, 4, 5, 9, 2, 6]Этот подход сохраняет порядок вставки и работает за O(n) — проверка in для множества выполняется за O(1). Сравните с проверкой if item not in result, которая занимает O(n) для каждого элемента и делает функцию O(n²) в целом.
Использование спискового включения
Тот же паттерн с множеством seen можно записать в одну строку с помощью спискового включения. Трюк состоит в том, что set.add() всегда возвращает None (ложное значение), поэтому выражение not (x in seen or seen.add(x)) равно True только при первом появлении каждого значения.
my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]
seen = set()
unique = [x for x in my_list if not (x in seen or seen.add(x))]
print(unique)Вывод:
[3, 1, 4, 5, 9, 2, 6]Такая запись компактна, но опирается на побочный эффект внутри включения, что может удивить читателя. Явный цикл выше зачастую предпочтительнее в командном коде.
Использование Counter для поиска дублирующихся значений
Иногда нужно знать, какие значения встречаются более одного раза, а не просто удалить их. collections.Counter подсчитывает вхождения и упрощает эту задачу.
from collections import Counter
my_list = [1, 2, 2, 3, 4, 4, 5, 5, 5]
counts = Counter(my_list)
print(counts)
duplicates = [item for item, count in counts.items() if count > 1]
print("Duplicated values:", duplicates)Вывод:
Counter({5: 3, 2: 2, 4: 2, 1: 1, 3: 1})
Duplicated values: [2, 4, 5]Чтобы получить дедуплицированный список из Counter, используйте list(counts.keys()) — ключи сохраняют порядок вставки в Python 3.7+.
Удаление дубликатов из DataFrame с помощью Pandas
Если вы работаете с табличными данными, библиотека Pandas предоставляет DataFrame.drop_duplicates(). Метод поддерживает точную настройку через параметры.
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob'],
'score': [90, 85, 90, 78, 85],
}
df = pd.DataFrame(data)
df_unique = df.drop_duplicates()
print(df_unique)Вывод:
name score
0 Alice 90
1 Bob 85
3 Charlie 78Ключевые параметры:
subset— имя столбца или список столбцов, по которым выполняется проверка. Дубликаты определяются только в рамках этих столбцов.keep—'first'(по умолчанию) сохраняет первое вхождение;'last'— последнее;Falseудаляет все строки, имеющие дубликаты.inplace=True— изменяет DataFrame на месте вместо возврата нового объекта.
# Keep only the last occurrence of each name
df_last = df.drop_duplicates(subset='name', keep='last')
print(df_last)Вывод:
name score
2 Alice 90
3 Charlie 78
4 Bob 85Выбор подходящего метода
- Максимальная скорость, порядок не важен —
set(). - Порядок важен, однострочное решение —
dict.fromkeys(). - Пользовательская логика или логирование — явный цикл for с множеством seen.
- Табличные данные —
pandas.DataFrame.drop_duplicates(). - Нужно узнать, какие значения дублируются —
collections.Counter.
Подробнее о работе со списками см. главу Python Lists и полный справочник методов списка. Чтобы узнать о множествах и операциях с ними, см. Python Sets и Set Methods.