Изучаем коллекции Python: выбор и эффективное использование

Раздел: Структуры данных -> Коллекции и структуры

Структуры данных в Python: выбор и практическое применение

Основной подход к выбору структуры данных в Python заключается в определении требований к изменяемости, упорядоченности и скорости доступа. Для задачи хранения упорядоченной последовательности, которую требуется изменять, оптимальным решением будет список (list). Если необходима неизменяемая последовательность, используется кортеж (tuple). Для быстрого поиска по ключу применяется словарь (dict), а для хранения уникальных элементов - множество (set). Каждая из этих структур имеет свою внутреннюю реализацию и область применения, что позволяет писать эффективный код.

Пример базового сравнения скорости доступа для словаря и списка:

import timeit

# Список
data_list = list(range(10000))
def search_list():
    return 9999 in data_list

# Словарь
data_dict = {i: i for i in range(10000)}
def search_dict():
    return 9999 in data_dict

print('List:', timeit.timeit(search_list, number=1000))
print('Dict:', timeit.timeit(search_dict, number=1000))

структуры данных в python (структуры данных в python)

List: 0.045
Dict: 0.0001

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

Как создать коллекцию неповторяющихся элементов и быстро проверять наличие?

Для хранения множества уникальных значений и операций принадлежности используется set. В отличие от списка, множество не сохраняет порядок и не допускает дубликатов.

unique_numbers = {1, 2, 3, 2, 1}
print(unique_numbers)
print(3 in unique_numbers)
{1, 2, 3}
True

Множество особенно полезно для удаления дубликатов из списка или быстрой проверки пересечения.

Типичная ошибка:

Попытка создать пустое множество через {} создаст словарь. Правильно: set().

Как организовать эффективную очередь с двусторонним доступом?

Модуль collections предоставляет deque (двусторонняя очередь), оптимизированную для добавления и удаления элементов с обоих концов со сложностью O(1).

from collections import deque

queue = deque([1, 2, 3])
queue.append(4)        # добавляем справа
queue.appendleft(0)    # добавляем слева
print(queue)
queue.pop()            # удаляем справа
queue.popleft()        # удаляем слева
print(queue)
deque([0, 1, 2, 3, 4])
deque([1, 2, 3])

Deque удобен для реализации очередей, стеков и буферов, где важна скорость операций на концах.

Типичная ошибка:

Использование списка для частого удаления первого элемента (pop(0)), что приводит к O(n) из-за сдвига элементов.

Как легко подсчитать количество вхождений каждого элемента в последовательности?

collections.Counter - это специализированный словарь для подсчета объектов. Он принимает любую итерируемую последовательность и возвращает словарь с частотами.

from collections import Counter

fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
counter = Counter(fruits)
print(counter)
print(counter.most_common(2))
Counter({'apple': 3, 'banana': 2, 'orange': 1})
[('apple', 3), ('banana', 2)]

Counter поддерживает арифметические операции, объединение и вычитание множеств.

Типичная ошибка:

Забыть импортировать Counter из collections. Без импорта возникнет NameError.

Как автоматически возвращать значение по умолчанию при обращении к отсутствующему ключу словаря?

collections.defaultdict позволяет указать фабрику по умолчанию для отсутствующих ключей. При обращении к несуществующему ключу создается новое значение с помощью фабрики.

from collections import defaultdict

# Словарь, где по умолчанию значение - пустой список
groups = defaultdict(list)
students = [('Math', 'Alice'), ('Math', 'Bob'), ('Physics', 'Charlie')]
for subject, name in students:
    groups[subject].append(name)
print(groups)
defaultdict(<class 'list'>, {'Math': ['Alice', 'Bob'], 'Physics': ['Charlie']})

Это избавляет от необходимости проверять наличие ключа и инициализировать значение вручную.

Типичная ошибка:

Попытка использовать обычный dict и получить KeyError при обращении к отсутствующему ключу.

Дополнительные примеры и продвинутые сценарии

Ниже приведены расширенные примеры использования структур данных, которые часто встречаются в реальных проектах.

Очередь с ограничением длины на основе deque

Пример
from collections import deque

# Очередь, хранящая только последние 5 элементов
recent = deque(maxlen=5)
for i in range(10):
    recent.append(i)
    print(recent)
deque([0], maxlen=5)
dequ([0, 1], maxlen=5)
...
dequ([5, 6, 7, 8, 9], maxlen=5)

При добавлении нового элемента, когда очередь полна, самый старый элемент автоматически удаляется. Это удобно для логирования последних событий.

Группировка записей по ключу с помощью defaultdict и сортировка

Пример
from collections import defaultdict

records = [('group1', 10), ('group2', 20), ('group1', 15), ('group2', 5)]
grouped = defaultdict(list)
for group, value in records:
    grouped[group].append(value)

# Сортировка ключей и вывод сумм
for group in sorted(grouped):
    total = sum(grouped[group])
    print(f'{group}: {total}')
group1: 25
group2: 25

Статистический анализ данных с Counter и объединение счетчиков

Пример
from collections import Counter

c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2, c=1)
# Сложение
combined = c1 + c2
print(combined)
# Вычитание (результат может содержать нулевые и отрицательные, которые игнорируются при выводе)
subtracted = c1 - c2
print(subtracted)
# Пересечение (минимум)
intersection = c1 & c2
print(intersection)
Counter({'a': 4, 'b': 3, 'c': 1})
Counter({'a': 2})
Counter({'a': 1, 'b': 1})

Именованные кортежи (namedtuple) для легковесных объектов данных

Пример
from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])
p1 = Point(10, 20)
p2 = Point(30, 40)
# Доступ по имени и по индексу
print(p1.x, p2[1])
# Распаковка
x, y = p1
print(x, y)
10 40
10 20

Namedtuple создает класс, экземпляры которого неизменяемы, но более эффективны по памяти, чем обычные словари. Подходит для хранения записей с фиксированными полями.

Структуры данных в Python - comments

En
структуры данных в python (python)