Как указывали другие ответы, вам не нужно беспокоиться, если ваш список oil_changes
не слишком длинный. Однако, как поклонник «потоковых» вычислений, я думаю, что интересно отметить, что itertools
предлагает все инструменты, необходимые для вычисления значения next_oil
в пространстве O (1) (и времени O (N) конечно! -) независимо от того, какой большой N, то есть len(next_oil)
, становится.
izip
само по себе недостаточно, потому что это только немного уменьшает мультипликативную константу, но оставляет ваши требования пространства как O (N). Основная идея довести эти требования до O (1) состоит в том, чтобы соединить izip
с tee
- и избегать понимания списка, которое в любом случае будет O (N) в пространстве, в пользу хорошего простого старого - вылепленная петля! -). Вот идет:
it = iter(oil_changes)
a, b = itertools.tee(it)
b.next()
thesum = 0
for thelen, (i, j) in enumerate(itertools.izip(a, b)):
thesum += j - i
last_one = j
next_oil = last_one + thesum / (thelen + 1)
Вместо того, чтобы брать кусочки из списка, мы берем итератор, делаем его (создаем два его независимо продвигаемых клона) и продвигаем, один раз, один из клонов, b
. tee
занимает пробел O (x), где x - максимальная абсолютная разница между продвижением различных клонов; здесь продвижение двух клонов отличается не более чем на 1, поэтому необходимое место явно равно O (1).
izip
выполняет поочередное «сжатие» двух итераторов клонов с небольшим перекосом, и мы одеваем их в enumerate
, чтобы мы могли отслеживать, сколько раз мы проходим цикл, т.е. длина итерируемой части, по которой мы итерируем (нам нужно +1 в конечном выражении, потому что enumerate
начинается с 0! -). Мы вычисляем сумму с помощью простого +=
, что хорошо для чисел (sum
еще лучше, но не будет отслеживать длину! -).
Заманчиво после цикла использовать last_one = a.next()
, но это не сработает, потому что a
фактически исчерпан - izip
продвигает свой аргумент итерируемо слева направо, поэтому он продвинулся a
в последний раз перед он понимает, что b
кончено! -). Это нормально, потому что переменные цикла Python НЕ ограничены по объему самим циклом - после цикла j
все еще имеет значение, которое было в последний раз извлечено путем продвижения b
до того, как izip
сдался (точно так же, как thelen
все еще имеет последнее значение счетчика, возвращаемое enumerate
). Я все еще называю значение last_one
вместо того, чтобы использовать j
непосредственно в конечном выражении, потому что я думаю, что оно более четкое и более читаемое.
Так что вот оно - надеюсь, это было поучительно! -) - хотя для решения конкретной проблемы, которую вы поставили на этот раз, это почти наверняка будет излишним. У нас, итальянцев, есть древняя пословица - «Impara l'Arte, e mettila da parte!» ... «Изучай искусство, а потом откладывай его в сторону» - что, я думаю, вполне применимо здесь: это хорошая вещь для изучения продвинутые и сложные способы решения очень сложных проблем, в случае, если вы когда-либо встречаете их, но при этом все, что вам нужно, - это стремление к простоте и прямоте в гораздо более распространенном случае простых, обычных проблем - не применять передовые решения, которые, скорее всего, выиграли не нужно! -)