Коллекции Python: список и множество - когда что выбрать

Раздел: Python -> Коллекции

Основные различия и варианты применения

Как эффективно удалить дубликаты из списка, сохранив порядок элементов?

Самое простое и быстрое решение для удаления повторяющихся элементов - использование set. Однако set не сохраняет порядок. Если порядок важен, применяется комбинация dict.fromkeys() (до Python 3.7 использовался OrderedDict), которая в Python 3.7+ гарантирует порядок вставки.


# Исходный список с дубликатами
original_list = [3, 1, 2, 3, 1, 4, 2]

# Удаление дубликатов с сохранением порядка (Python 3.7+)
unique_ordered = list(dict.fromkeys(original_list))
print(unique_ordered)  # [3, 1, 2, 4]
    

Python set list (set и list в python: различия и использование)

Пояснение: dict.fromkeys() создаёт словарь, где ключи - элементы списка, а значения - None. Поскольку ключи уникальны, дубликаты отбрасываются, а порядок вставки сохраняется.

Типичная ошибка: использование set() напрямую, если порядок важен. Решение: применить описанный выше способ или OrderedDict для старых версий Python.

Как проверить, есть ли элемент в коллекции, и почему set быстрее?

Для проверки принадлежности элемента (in) set имеет среднюю сложность O(1), а list - O(n). Это особенно заметно на больших объёмах данных.


# Список и множество из 10 000 элементов
big_list = list(range(10000))
big_set = set(big_list)

import time

start = time.perf_counter()
for _ in range(1000):
    9999 in big_list
print('list:', time.perf_counter() - start)

start = time.perf_counter()
for _ in range(1000):
    9999 in big_set
print('set:', time.perf_counter() - start)
    

Python пары значений (пары значений в python)

list: ~0.05-0.1 сек
set:  ~0.0001-0.0002 сек
    

Python object get (метод get для объектов в python)

Цель: когда требуется частая проверка вхождения, выбирают set. Если же коллекция маленькая или проверки редки, разница несущественна.

Проблема: set не поддерживает индексацию и не упорядочен (до Python 3.7 порядок не гарантирован, после - сохраняется порядок вставки, но не сортировка). Решение: если нужен доступ по индексу, следует использовать list.

Какие математические операции над множествами можно выполнить с set, и как имитировать их для list?

Set предоставляет встроенные методы для объединения, пересечения, разности и симметрической разности. Для списков эти операции приходится реализовывать вручную, что менее эффективно.


set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}

print('Объединение:', set_a | set_b)          # {1,2,3,4,5,6}
print('Пересечение:', set_a & set_b)          # {3,4}
print('Разность:', set_a - set_b)             # {1,2}
print('Симметрич. разность:', set_a ^ set_b)  # {1,2,5,6}

# Аналог для списков (без учёта дубликатов)
list_a = [1,2,3,4]
list_b = [3,4,5,6]
union = list(set(list_a) | set(list_b))       # преобразование в set и обратно
    

Python get keys (метод get для словарей в python)

Пояснение: методы union, intersection и т.д. работают с любыми итерируемыми объектами, но возвращают множество.

Ошибка: попытка выполнить пересечение двух списков напрямую через & вызывает TypeError. Решение: преобразовать в set, выполнить операцию, затем обратно в list (если порядок не важен). Если порядок важен, придётся использовать списковые включения.

Когда следует использовать list вместо set?

List незаменим, когда:

  • требуется сохранить порядок элементов (в том числе сортированный);
  • нужен доступ по индексу или срезы;
  • элементы могут повторяться;
  • элементы не хешируемы (например, другие списки). Set может содержать только хешируемые объекты (числа, строки, кортежи, frozenset).

# list можно сортировать и обращаться по индексу
fruits = ['banana', 'apple', 'cherry']
fruits.sort()
print(fruits[0])  # apple

# set - неупорядоченная коллекция, но можно отсортировать при выводе
nums = {3, 1, 2}
print(sorted(nums))  # [1, 2, 3]
    

Get index python (метод index в python)

Проблема: попытка добавить список в set приводит к TypeError: unhashable type: 'list'. Решение: использовать кортежи или frozenset.

Как правильно выбрать между list и set при решении конкретной задачи?

Критерии выбора:

  • Нужна ли уникальность? Если да, то set.
  • Важен ли порядок? Если да, и дубликаты недопустимы - list + ручное управление дубликатами (или set с последующей сортировкой, если порядок не вставки).
  • Часто ли проверяется вхождение? При большом количестве проверок - set.
  • Нужны ли математические операции над множествами? - set.
  • Элементы являются изменяемыми объектами? - только list.

# Пример: поиск общих друзей (множества)
my_friends = {'Alice', 'Bob', 'Charlie'}
your_friends = {'Bob', 'Diana', 'Eve'}
common = my_friends & your_friends
print(common)  # {'Bob'}

# Пример: список покупок (порядок и дубликаты возможны)
shopping = ['milk', 'eggs', 'milk', 'bread']
    
- словарь данных python (словарь данных в python)
- типы данных python кортеж (кортеж (tuple) в python)
- Python типы данных set (множество (set) в python)

Дополнительные примеры и тонкости работы с Set и List

1. Вложенные множества и кортежи

Поскольку set требует хешируемых элементов, для хранения наборов значений внутри множества используют frozenset или кортежи.

Пример

# frozenset внутри set
set_of_sets = {frozenset({1,2}), frozenset({3,4})}
print(set_of_sets)  # {frozenset({1, 2}), frozenset({3, 4})}

# Кортежи внутри set
pairs = {(1,2), (3,4), (1,2)}
print(pairs)  # {(1, 2), (3, 4)} - дубликат удалён

2. Преобразование list в set и обратно с сохранением порядка

Если нужно удалить дубликаты и сохранить порядок первого вхождения, можно использовать dict.fromkeys (как в основном решении). Альтернатива с ручным циклом:

Пример

items = ['a', 'b', 'a', 'c', 'b']
seen = set()
result = []
for item in items:
    if item not in seen:
        seen.add(item)
        result.append(item)
print(result)  # ['a', 'b', 'c']

3. Сравнение скорости: list vs set при добавлении элементов

Пример

import time

n = 100000
start = time.perf_counter()
s = set()
for i in range(n):
    s.add(i)
print('set add:', time.perf_counter() - start)

start = time.perf_counter()
l = []
for i in range(n):
    l.append(i)
print('list append:', time.perf_counter() - start)
set add: ~0.02 сек
list append: ~0.01 сек

Пояснение: добавление в list быстрее, так как не требует вычисления хеша и проверки уникальности. Однако поиск элемента в list медленнее.

4. Использование set для фильтрации списка (удаление элементов, присутствующих в другом списке)

Пример

all_users = ['Alice', 'Bob', 'Charlie', 'Diana']
blocked = {'Bob', 'Diana'}
active = [user for user in all_users if user not in blocked]
print(active)  # ['Alice', 'Charlie']

Преимущество: проверка вхождения в set работает быстро.

5. Ошибка при попытке изменить элемент set

Set - изменяемая коллекция, но сами элементы должны быть неизменяемыми. Попытка модифицировать кортеж, находящийся внутри set, приведёт к ошибке, так как кортежи неизменяемы. Однако можно удалить старый элемент и добавить новый.

Пример

s = {(1,2), (3,4)}
# Ошибка: tuple не поддерживает присваивание
# s[0] = (5,6)  # TypeError

# Правильное изменение: удаление и добавление
s.remove((1,2))
s.add((5,6))
print(s)  # {(3,4), (5,6)}

6. List и set как изменяемые коллекции: разница в мутабельности

Обе коллекции изменяемы, но при попытке использовать list как ключ словаря или элемент set возникнет ошибка. Set допускает только неизменяемые элементы.

Пример

try:
    s = {[1,2]}  # TypeError
except TypeError as e:
    print(e)  # unhashable type: 'list'

# Рабочий вариант: кортеж
s = {(1,2)}
print(s)

7. Имитация операций над множествами для списков с помощью включений

Пример

list_a = [1,2,3,3,4]
list_b = [3,4,5,6]

# Пересечение (только уникальные, порядок не гарантирован)
intersection = [x for x in set(list_a) if x in set(list_b)]
print(intersection)  # [3,4]

# Разность (элементы list_a, которых нет в list_b)
diff = [x for x in set(list_a) if x not in set(list_b)]
print(diff)  # [1,2]

Замечание: включение преобразует списки в set для быстрой проверки, что эффективнее, чем проверка in на списке.

8. Использование frozenset как неизменяемого аналога set

frozenset - неизменяемое множество, может быть элементом другого set или ключом словаря.

Пример

fs = frozenset([1,2,3])
d = {fs: 'value'}
print(d)  # {frozenset({1, 2, 3}): 'value'}

# Попытка изменить frozenset вызовет ошибку
# fs.add(4)  # AttributeError

Set и List в Python: различия и использование - comments

En
Python set list (python)