Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Зачем нужен Set в Python
Set — это одна из самых недооценённых структур данных в Python. Её часто путают с List и Dict, но она решает совершенно специфические задачи. Разберусь подробно.
Основная идея: уникальность и скорость
Set — это неупорядоченная коллекция уникальных элементов. В отличие от List, Set:
- Не хранит дубликаты: если добавить один элемент дважды, он останется в одной копии
- Очень быстро ищет элементы: O(1) вместо O(n) как в List
- Использует хеширование: элементы должны быть hashable (неизменяемые)
# List: медленная проверка наличия элемента
my_list = [1, 2, 3, 4, 5]
if 3 in my_list: # O(n) — проверяет каждый элемент
print("Found")
# Set: быстрая проверка
my_set = {1, 2, 3, 4, 5}
if 3 in my_set: # O(1) — прямой доступ
print("Found")
Зачем нужен Set: основные применения
1. Удаление дубликатов
Это самая частая задача:
# Задача: удалить дубликаты из списка
numbers = [1, 2, 3, 2, 4, 1, 5, 3]
# Способ 1: через Set (самый быстрый)
unique_numbers = list(set(numbers))
print(unique_numbers) # [1, 2, 3, 4, 5]
# Способ 2: через List comprehension (медленнее, но сохраняет порядок)
seen = set()
unique_numbers = [x for x in numbers if not (x in seen or seen.add(x))]
# Способ 3: dict.fromkeys() (Python 3.7+, сохраняет порядок)
unique_numbers = list(dict.fromkeys(numbers))
Обработка миллионов элементов:
import time
numbers = list(range(1000000)) * 10 # 10 миллионов элементов
# Set: очень быстро
start = time.time()
unique = set(numbers)
print(f"Set: {time.time() - start:.4f}s") # ~0.05s
# List с проверкой: медленно
start = time.time()
unique = []
for num in numbers:
if num not in unique: # O(n) проверка!
unique.append(num)
print(f"List: {time.time() - start:.4f}s") # ~60s
2. Проверка наличия элемента
Eсли часто проверяешь наличие элемента — используй Set:
# Задача: проверить, есть ли в списке запрещённые слова
banned_words = ['spam', 'abuse', 'hate']
# МЕДЛЕННО: O(n) для каждой проверки
text = "This is a message".split()
for word in text:
if word.lower() in banned_words: # O(n)
print(f"Banned: {word}")
# БЫСТРО: O(1) для каждой проверки
banned_words_set = {'spam', 'abuse', 'hate'}
for word in text:
if word.lower() in banned_words_set: # O(1)
print(f"Banned: {word}")
Для большого количества проверок разница критична:
# 10 миллионов проверок
banned = set(open('banned_words.txt').read().split())
text_tokens = [...] # 10 млн слов
for token in text_tokens:
if token in banned: # O(1) — мгновенно
# обработка
3. Операции с множествами
Set поддерживает математические операции над множествами:
set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}
# Пересечение (AND): элементы, которые есть в обоих
intersection = set_a & set_b
print(intersection) # {3, 4}
# Объединение (OR): все уникальные элементы
union = set_a | set_b
print(union) # {1, 2, 3, 4, 5, 6}
# Разность (MINUS): элементы только в первом
difference = set_a - set_b
print(difference) # {1, 2}
# Симметричная разность (XOR): элементы в одном, но не в обоих
sym_diff = set_a ^ set_b
print(sym_diff) # {1, 2, 5, 6}
# Проверка подмножества
small = {1, 2}
if small <= set_a: # True
print("small is subset of set_a")
Практический пример: найти общих друзей
alice_friends = {'Bob', 'Charlie', 'David', 'Eve'}
bob_friends = {'Alice', 'Charlie', 'Frank', 'Grace'}
# Кто есть в друзьях у обоих?
common_friends = alice_friends & bob_friends
print(common_friends) # {'Charlie'}
# Кого знает Alice, но не Bob?
only_alice = alice_friends - bob_friends
print(only_alice) # {'Bob', 'David', 'Eve'}
4. Дедупликация в потоке данных
# Задача: найти все уникальные IP адреса в логах
with open('access.log') as f:
unique_ips = set()
for line in f:
ip = line.split()[0]
unique_ips.add(ip)
print(f"Total unique IPs: {len(unique_ips)}")
# Это очень быстро, даже для файлов в гигабайты
# Потому что Set хранит только хеш (8-16 байт), не сам IP
5. Отслеживание состояния
# Задача: отслеживать, какие пользователи онлайн
class ChatRoom:
def __init__(self):
self.online_users = set() # Быстрая проверка: есть ли пользователь онлайн?
def user_joined(self, user_id):
self.online_users.add(user_id)
def user_left(self, user_id):
self.online_users.discard(user_id) # remove() вызывает ошибку, если нет
def is_online(self, user_id):
return user_id in self.online_users # O(1)
def get_online_count(self):
return len(self.online_users)
Set vs List vs Dict: когда что использовать
# ИСПОЛЬЗУЙ LIST ЕСЛИ:
# - Нужен порядок элементов
# - Нужен доступ по индексу
# - Допускаются дубликаты
scores = [100, 95, 87, 92] # Порядок важен
first = scores[0] # Доступ по индексу
# ИСПОЛЬЗУЙ SET ЕСЛИ:
# - Нужна уникальность
# - Часто проверяешь наличие элемента
# - Нужны операции над множествами
visited = {1, 2, 3} # Быстрая проверка 'if x in visited'
unique = set([1, 2, 2, 3]) # Автоматически удаляет дубликаты
# ИСПОЛЬЗУЙ DICT ЕСЛИ:
# - Нужна связь ключ-значение
# - Нужен быстрый поиск по ключу
user_ages = {'Alice': 30, 'Bob': 25} # Ключ → значение
Важные характеристики Set
# Set содержит только hashable элементы
my_set = {1, 'hello', (1, 2)} # Можно: int, str, tuple
# ОШИБКА: list не hashable
my_set = {1, [2, 3]} # TypeError!
# ОШИБКА: dict не hashable
my_set = {1, {'key': 'value'}} # TypeError!
# Но frozenset (неизменяемый set) — hashable
my_set = {1, frozenset([2, 3])} # Ок!
# Set сам является изменяемым, поэтому не может быть ключом dict
my_dict = {(1, 2): 'value'} # Ок! Tuple hashable
my_dict = {{1, 2}: 'value'} # TypeError!
my_dict = {frozenset([1, 2]): 'value'} # Ок!
Производительность
import timeit
# Проверка наличия элемента в 1 миллион элементов
my_list = list(range(1000000))
my_set = set(range(1000000))
list_time = timeit.timeit(lambda: 999999 in my_list, number=100)
set_time = timeit.timeit(lambda: 999999 in my_set, number=100)
print(f"List: {list_time:.4f}s") # ~0.1s
print(f"Set: {set_time:.4f}s") # ~0.001s (в 100 раз быстрее!)
Выводы
Set нужен для:
- Удаления дубликатов — самый быстрый способ
- Быстрого поиска элементов — O(1) вместо O(n)
- Операций над множествами — пересечение, объединение, разность
- Отслеживания уникальности — какие ID уже видели
- Работы с большими данными — Set экономит память и время
Золотое правило: если часто проверяешь наличие элемента или нужна уникальность — используй Set, не List!