Когда в Python следует использовать collections.deque вместо списка?

Ответ

collections.deque (двусторонняя очередь) следует использовать вместо списка (list), когда требуется быстрое добавление и удаление элементов с обоих концов коллекции.

Ключевое отличие: Производительность

  • deque: Операции append, pop, appendleft, popleft имеют амортизированную сложность O(1).
  • list: append и pop (с конца) также имеют сложность O(1), но insert(0, ...) и pop(0) (с начала) требуют сдвига всех элементов и имеют сложность O(n).

Основные сценарии использования deque:

  1. Реализация очередей (FIFO): Использовать append для добавления и popleft для извлечения.
  2. Скользящее окно: Хранение N последних элементов из потока данных с помощью параметра maxlen.
  3. Алгоритмы обхода графов (BFS): Где требуется эффективная очередь для хранения вершин.

Пример:

from collections import deque

# 1. Быстрые операции с обоих концов
d = deque([1, 2, 3])
d.appendleft(0)  # O(1) -> deque([0, 1, 2, 3])
d.append(4)      # O(1) -> deque([0, 1, 2, 3, 4])
d.popleft()      # O(1) -> возвращает 0, d = deque([1, 2, 3, 4])

# 2. Ограничение размера (скользящее окно)
last_five_logs = deque(maxlen=5)
for i in range(10):
    last_five_logs.append(f"Log entry {i}")

# deque автоматически удаляет старые элементы
print(last_five_logs) 
# Вывод: deque(['Log entry 5', 'Log entry 6', 'Log entry 7', 'Log entry 8', 'Log entry 9'], maxlen=5)

Вывод: Если вам нужна структура данных, оптимизированная для операций в начале и в конце, deque — лучший выбор. Для произвольного доступа по индексу и операций в середине коллекции list остается более эффективным.

Ответ 18+ 🔞

Ага, слушай, вот эта штука collections.deque — это же просто пиздец какой полезный инструмент, если тебе надо быстро пихать и вытаскивать элементы с обоих концов. Представь себе обычный список (list), он же, блядь, как упрямая скотина: добавить что-то в конец — легко, О(1). Но стоит тебе захотеть сунуть что-то в начало — insert(0, ...) — он начинает охуевать и двигать ВСЕ элементы, это уже О(n), ёпта! А если элементов овердохуища? Пиздец, а не производительность.

А вот deque — это как хитрая жопа с двумя карманами. Туда-сюда, в начало, в конец — всё за О(1), потому что внутри это связный список, а не массив. Красота!

Так когда его юзать, спросишь ты?

  1. Очередь (FIFO), блядь! Самый классический случай. append — добавил в хвост, popleft() — вытащил из головы. Идеально для задач, где "первым пришел — первым ушел". Никаких тебе pop(0) из списка, которые всё ломают.
  2. Скользящее окно, ёбушки-воробушки! Вот тебе поток данных, а тебе надо хранить только последние N штук. Задаёшь maxlen при создании — и всё, он сам, сука, старые записи выкидывает, когда новые приходят. Удобнее некуда.
  3. Обход графа в ширину (BFS). Там же очередь вершин нужна. deque — то, что доктор прописал.

Смотри, как это выглядит в коде:

from collections import deque

# 1. Быстрые операции с обоих концов — это просто песня!
d = deque([1, 2, 3])
d.appendleft(0)  # O(1) — бац, и в начале ноль! deque([0, 1, 2, 3])
d.append(4)      # O(1) — и в конец четвёрка! deque([0, 1, 2, 3, 4])
x = d.popleft()  # O(1) — выдернул первый элемент (0), d = deque([1, 2, 3, 4])
print(f"Вытащил: {x}, осталось: {d}")

# 2. Скользящее окно — вообще магия, ядрёна вошь!
last_five_logs = deque(maxlen=5) # Всё, больше пяти не влезет
for i in range(10):
    last_five_logs.append(f"Запись лога {i}")
    # После каждого шага смотри, как оно само чистится

print("Последние 5 записей:", last_five_logs)
# Вывод: deque(['Запись лога 5', 'Запись лога 6', 'Запись лога 7', 'Запись лога 8', 'Запись лога 9'], maxlen=5)
# Видишь? Записи 0-4 сами, нахуй, испарились! Красота.

Итог, чувак: Если тебе надо быстро работать с головами и хвостами — бери deque и не парься. Если же тебе надо постоянно лазить по индексам где-то в середине или менять элементы — тут уже list рулит. Каждый инструмент для своего дела, ёпта. Главное — не пытайся забивать гвозди микроскопом, а то получишь пиздопроебибну.