5

我有一个看起来像这样的元组列表:

lst = [(0, 0), (2, 3), (4, 3), (5, 1)]

累积第一个和第二个元组元素之和的最佳方法是什么?使用上面的示例,我正在寻找生成此列表的最佳方法:

new_lst = [(0, 0), (2, 3), (6, 6), (11, 7)]

我正在寻找 Python 2.6 中的解决方案

4

9 回答 9

14

我认为最好的解决方案是itertools.accumulate()累积值,并zip()用来拆分列并将它们合并回来。这意味着生成器只处理单个列,并使该方法完全可扩展。

>>> from itertools import accumulate
>>> lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
>>> list(zip(*map(accumulate, zip(*lst))))
[(0, 0), (2, 3), (6, 6), (11, 7)]

我们zip()用来取列,然后应用itertools.accumulate()到每一列,然后zip()用来将它们合并回原始格式。

此方法适用于任何可迭代的,而不仅仅是序列,并且应该相对有效。

在 3.2 之前,accumulate 可以定义为:

def accumulate(iterator):
    total = 0
    for item in iterator:
        total += item
        yield total

(文档页面提供了更通用的实现,但对于这个用例,我们可以使用这个简单的实现)。

于 2013-05-07T17:49:08.070 回答
3

这个生成器怎么样:

def accumulate_tuples(iterable):
    accum_a = accum_b = 0
    for a, b in iterable:
        accum_a += a
        accum_b += b
        yield accum_a, accum_b

如果您需要列表,只需调用list(accumulate_tuples(your_list)).

这是一个适用于任意长度元组的版本:

def accumulate_tuples(iterable):
    it = iter(iterable):
    accum = next(it) # initialize with the first value
    yield accum
    for val in it: # iterate over the rest of the values
        accum = tuple(a+b for a, b in zip(accum, val))
        yield accum
于 2013-05-07T17:48:42.430 回答
2

这适用于任何长度的tuples 或其他iterables。

from collections import defaultdict

def accumulate(lst):
    sums = defaultdict(int)
    for item in lst:
        for index, subitem in enumerate(item):
            sums[index] += subitem
        yield [sums[index] for index in xrange(len(sums))]

print [tuple(x) for x in accumulate([(0, 0), (2, 3), (4, 3), (5, 1)])]

在 Python 2.7+ 中,您将使用 aCounter而不是defaultdict(int).

于 2013-05-07T17:49:43.940 回答
2
>> reduce(lambda x,y: (x[0] + y[0], x[1] + y[1]), lst)
 (11, 7)

编辑。我可以看到你更新的问题。要获取运行列表,您可以执行以下操作:

>> [reduce(lambda x,y: (x[0]+y[0], x[1]+y[1]), lst[:i]) for i in range(1,len(lst)+1)]
[(0, 0), (2, 3), (6, 6), (11, 7)]

不是超级高效,但至少它可以工作并且做你想要的:)

于 2013-05-07T17:43:12.217 回答
1

这是一种非常糟糕的方法(就性能而言),因为list.append它很昂贵,但它确实有效。

last = lst[0]
new_list = [last]
for t in lst[1:]:
    last += t
    new_list.append(last)
于 2013-05-07T17:40:55.230 回答
0
lst = [(0, 0), (2, 3), (4, 3), (5, 1)]

lst2 = [lst[0]]
for idx in range(1, len(lst)):
    newItem = [0,0]
    for idx2 in range(0, idx + 1):
        newItem[0] = newItem[0] + lst[idx2][0]
        newItem[1] = newItem[1] + lst[idx2][1]
    lst2.append(newItem)

print(lst2)
于 2013-05-07T17:48:16.963 回答
0

简单方法:

>> x = [(0, 0), (2, 3), (4, 3), (5, 1)]
>>> [(sum(a for a,b in x[:t] ),sum(b for a,b in x[:t])) for t in range(1,len(x)+1)]
[(0, 0), (2, 3), (6, 6), (11, 7)]
于 2013-05-07T17:43:17.587 回答
0

将我的代码更改为更简洁的版本:

lst = [(0, 0), (2, 3), (4, 3), (5, 1)]

def accumulate(the_list):
    the_item = iter(the_list)
    accumulator = next(the_item)
    while True:
        yield accumulator
        accumulator = tuple(x+y for (x,y) in zip (accumulator, next(the_item)))

new_lst = list(accumulate(lst))
于 2013-05-07T17:52:59.697 回答
0

您可以使用以下功能

>>> def my_accumulate(lst):
      new_lst = [lst[0]]
      for x, y in lst[1:]:
        new_lst.append((new_lst[-1][0]+x, new_lst[-1][1]+y))
      return new_lst

>>> lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
>>> my_accumulate(lst)
[(0, 0), (2, 3), (6, 6), (11, 7)]
于 2013-05-07T17:41:50.397 回答