Список понимания для подведения итогов - PullRequest
23 голосов
/ 08 августа 2010

Я хочу получить промежуточную сумму из списка чисел.

В демонстрационных целях я начинаю с последовательного списка чисел, используя range

a = range(20)

runningTotal = []
for n in range(len(a)):
    new = runningTotal[n-1] + a[n] if n > 0 else a[n]
    runningTotal.append(new)

# This one is a syntax error
# runningTotal = [a[n] for n in range(len(a)) if n == 0 else runningTotal[n-1] + a[n]]

for i in zip(a, runningTotal):
    print "{0:>3}{1:>5}".format(*i)

выходы

  0    0
  1    1
  2    3
  3    6
  4   10
  5   15
  6   21
  7   28
  8   36
  9   45
 10   55
 11   66
 12   78
 13   91
 14  105
 15  120
 16  136
 17  153
 18  171
 19  190

Как видите, я инициализирую пустой список [], затем append() в каждой итерации цикла. Есть ли более элегантный способ для этого, как понимание списка?

Ответы [ 13 ]

0 голосов
/ 27 апреля 2019

Начиная с Python 3.8 и введением выражений присваивания (PEP 572) (оператор :=), мы можем использовать и увеличивать переменную в пределах списка:

# items = range(7)
total = 0
[(x, total := total + x) for x in items]
# [(0, 0), (1, 1), (2, 3), (3, 6), (4, 10), (5, 15), (6, 21)]

This:

  • Инициализирует переменную total до 0, которая символизирует текущую сумму
  • Для каждого элемента это оба:
    • приращения total текущим зацикленным элементом (total := total + x) через выражение присваивания
    • и в то же время возвращает новое значение total как часть созданного отображенного кортежа
0 голосов
/ 08 августа 2010

Вы ищете две вещи: сложение (уменьшение) и забавную функцию, которая хранит список результатов другой функции, которую я назвал запущенной. Я сделал версии как с начальным параметром, так и без него; в любом случае их нужно уменьшить с начальным [].

def last_or_default(list, default):
    if len(list) > 0:
        return list[-1]
    return default

def initial_or_apply(list, f, y):
    if list == []:
        return [y]
    return list + [f(list[-1], y)]

def running_initial(f, initial):
    return (lambda x, y: x + [f(last_or_default(x,initial), y)])

def running(f):
    return (lambda x, y: initial_or_apply(x, f, y))

totaler = lambda x, y: x + y
running_totaler = running(totaler)
running_running_totaler = running_initial(running_totaler, [])

data = range(0,20)
running_total = reduce(running_totaler, data, [])
running_running_total = reduce(running_running_totaler, data, [])

for i in zip(data, running_total, running_running_total):
    print "{0:>3}{1:>4}{2:>83}".format(*i)

Это займет много времени в действительно больших списках из-за оператора +. На функциональном языке, если все сделано правильно, эта конструкция списка будет O (n).

Вот первые несколько строк вывода:

0   0                      [0]
1   1                   [0, 1]
2   3                [0, 1, 3]
3   6             [0, 1, 3, 6]
4  10         [0, 1, 3, 6, 10]
5  15     [0, 1, 3, 6, 10, 15]
6  21 [0, 1, 3, 6, 10, 15, 21]
0 голосов
/ 08 августа 2010

Это неэффективно, так как это происходит каждый раз с начала, но возможно:

a = range(20)
runtot=[sum(a[:i+1]) for i,item in enumerate(a)]
for line in zip(a,runtot):
    print line
...