Краткий ответ
Данный фрагмент кода выполняет последовательные конкатенации списков.
Как это работает
Грубо говоря, встроенная сумма ( ) функция работает следующим образом:
def sum(iterable, /, start=0):
total = start
for x in iterable:
total = total + x
return total
Оператор +
вызывает __add__
для левого операнда, так что 3 + 4
работает как (3).__add__(4)
, операция сложения на целых числах. Аналогично, [10, 20] + [30, 40, 50]
запускается как [10, 20].__add__([30, 40, 50])
, операция объединения в списки.
Вот как это работает в данном примере:
>>> nums = [1,2,3,4]
>>> g = ([b] * a for a, b in zip(nums[::2], nums[1::2]))
>>> result = []
>>> x = next(g)
>>> result = result + x
>>> result
[2]
>>> x = next(g)
>>> result = result + x
>>> result
[2, 4, 4, 4]
Почему это не очень хорошая идея
Последовательные конкатенации списков создают следующий список после каждого добавления, поэтому они работают со скоростью O(n**2)
, что означает, что это алгоритм квадратичного c, который работает чрезмерно медленно при наличии больших входных данных.
Лучший способ
Вместо создания новых списков на каждом шаге, просто расширить базовый список на месте. Это работает на O(n)
линейной скорости:
>>> nums = [1,2,3,4]
>>> g = ([b] * a for a, b in zip(nums[::2], nums[1::2]))
>>> result = [] # new list
>>> for x in g:
result.extend(x) # extend in-place
>>> result
[2, 4, 4, 4]
Еще лучше
Модуль itertools предоставляет инструмент для создания цепочек вместе итераторы . Это облегчает проблему:
>>> nums = [1,2,3,4]
>>> g = ([b] * a for a, b in zip(nums[::2], nums[1::2]))
>>> list(chain.from_iterable(g))
[2, 4, 4, 4]
Это решение короткое, быстрое и хорошо работает даже при больших входах.