Изучаем коллекции 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 создает класс, экземпляры которого неизменяемы, но более эффективны по памяти, чем обычные словари. Подходит для хранения записей с фиксированными полями.