← Назад к вопросам
Как сделать все значения списка (list) уникальными?
1.2 Junior🔥 81 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как сделать все значения списка (list) уникальными
Удаление дубликатов из списка — частая задача. Есть несколько подходов с разными характеристиками по производительности и сохранению порядка.
1. Использование set() — простейший подход
numbers = [1, 2, 2, 3, 3, 3, 4]
unique_numbers = list(set(numbers))
print(unique_numbers) # [1, 2, 3, 4] или другой порядок
Плюсы:
- Самый быстрый способ O(n)
- Код простой и понятный
Минусы:
- НЕ сохраняет порядок элементов
- Не работает с неhashable типами (списки, словари, множества)
2. Сохранение порядка с dict.fromkeys()
numbers = [1, 2, 2, 3, 3, 3, 4, 5, 1]
unique_numbers = list(dict.fromkeys(numbers))
print(unique_numbers) # [1, 2, 3, 4, 5]
Как это работает:
dict.fromkeys()создаёт словарь с уникальными ключами- С Python 3.7+ словари сохраняют порядок вставки
list()конвертирует ключи словаря обратно в список
Плюсы:
- Быстрый O(n)
- Сохраняет оригинальный порядок
- Чистый и понятный код
Минусы:
- Не работает с неhashable типами
3. Циклический подход с проверкой
numbers = [1, 2, 2, 3, 3, 3, 4]
unique_numbers = []
for num in numbers:
if num not in unique_numbers:
unique_numbers.append(num)
print(unique_numbers) # [1, 2, 3, 4]
Плюсы:
- Сохраняет порядок
- Работает с любыми типами
- Понятный код
Минусы:
- Медленный O(n²) — проверка в списке для каждого элемента
- Неэффективно для больших списков
4. Использование set для отслеживания
numbers = [1, 2, 2, 3, 3, 3, 4]
seen = set()
unique_numbers = []
for num in numbers:
if num not in seen:
seen.add(num)
unique_numbers.append(num)
print(unique_numbers) # [1, 2, 3, 4]
Плюсы:
- Сохраняет порядок
- Быстрый O(n) — проверка в set
- Работает с hashable типами
Минусы:
- Немного больше кода
5. Для неhashable типов (списки, словари)
data = [
{"id": 1, "name": "Alice"},
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"},
]
# Способ 1: Конвертировать в tuple для hashable типа
from typing import Any
def make_hashable(obj: Any) -> Any:
if isinstance(obj, dict):
return tuple(sorted(obj.items()))
elif isinstance(obj, list):
return tuple(make_hashable(item) for item in obj)
return obj
unique_data = []
seen = set()
for item in data:
hashable = make_hashable(item)
if hashable not in seen:
seen.add(hashable)
unique_data.append(item)
print(unique_data)
# [
# {"id": 1, "name": "Alice"},
# {"id": 2, "name": "Bob"},
# ]
6. Использование library функций
pandas для больших данных:
import pandas as pd
numbers = [1, 2, 2, 3, 3, 3, 4]
unique_numbers = pd.Series(numbers).drop_duplicates().tolist()
print(unique_numbers) # [1, 2, 3, 4]
Для объектов с ID (например, БД запросы):
users = [
{"id": 1, "name": "Alice"},
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"},
]
unique_users = {
user["id"]: user
for user in users
}.values()
print(list(unique_users))
7. Сравнение производительности
import time
numbers = list(range(10000)) * 10 # 100000 элементов
# Способ 1: set()
start = time.time()
result = list(set(numbers))
print(f"set(): {time.time() - start:.4f}s")
# Способ 2: dict.fromkeys()
start = time.time()
result = list(dict.fromkeys(numbers))
print(f"dict.fromkeys(): {time.time() - start:.4f}s")
# Способ 3: Цикл с set
start = time.time()
seen = set()
result = []
for num in numbers:
if num not in seen:
seen.add(num)
result.append(num)
print(f"цикл + set: {time.time() - start:.4f}s")
# Способ 4: Цикл с проверкой в списке
start = time.time()
result = []
for num in numbers:
if num not in result:
result.append(num)
print(f"цикл в списке: {time.time() - start:.4f}s") # Медленный!
Результаты (примерно):
set(): 0.0001s ✓ Быстро
dict.fromkeys(): 0.0005s ✓ Быстро, сохраняет порядок
цикл + set: 0.0008s ✓ Быстро
цикл в списке: 2.5000s ✗ МЕДЛЕННО!
8. Практические примеры
Удаление дубликатов из тегов:
def normalize_tags(tags: list[str]) -> list[str]:
"""Удаляет дубликаты и нормализует теги"""
# Преобразуем, убираем пробелы, приводим к нижнему регистру
normalized = [tag.strip().lower() for tag in tags]
# Удаляем дубликаты, сохраняя порядок
return list(dict.fromkeys(normalized))
tags = ["Python", "python", "Django", "Python", "Flask"]
print(normalize_tags(tags)) # ["python", "django", "flask"]
Удаление дубликатов в потоке данных (generator):
def unique_iterator(iterable):
"""Генератор для удаления дубликатов из потока"""
seen = set()
for item in iterable:
if item not in seen:
seen.add(item)
yield item
# Использование
data = [1, 2, 2, 3, 3, 3]
for unique in unique_iterator(data):
print(unique) # 1, затем 2, затем 3
Для объектов по определённому полю:
class User:
def __init__(self, id, name):
self.id = id
self.name = name
users = [
User(1, "Alice"),
User(1, "Alice"),
User(2, "Bob"),
]
# Удаляем дубликаты по ID
unique_users = {user.id: user for user in users}.values()
print(list(unique_users)) # 2 пользователя
Рекомендации по выбору
| Ситуация | Метод | Примечание |
|---|---|---|
| Просто удалить дубликаты | list(set(list)) | Если порядок не важен |
| Сохранить порядок | list(dict.fromkeys(list)) | Обычное решение |
| Большие данные | pandas или numpy | Для оптимизации памяти |
| Неhashable типы | Цикл + set с hashable ключами | Или dict.fromkeys с ключом |
| Потоковая обработка | Generator с set | Для больших данных |
Лучшие практики
- По умолчанию используй
dict.fromkeys()— быстро, сохраняет порядок, понятно - Если порядок не важен, используй
set()— на микросекунду быстрее - Избегай циклических проверок в списке — O(n²) очень медленно
- Для больших данных профилируй — используй
timeitдля сравнения - Документируй намерение — почему удаляешь дубликаты и какой порядок нужен