Python将相对更改的有序列表转换为绝对更改

时间:2012-05-22 19:42:27

标签: python

假设我有一组对象包含:(相对变化,变化时间):

(+1,0) (-1, 1) (+1,3) (+1, 3) (-1, 5) (+1, 9)  

现在我想用绝对值替换相对变化,从0开始:

(1,0) (0, 1) (1,3) (2, 3) (1, 5) (2, 9)
 0+1   0+1-1  0+1-1+1 ...

最好的方法是什么?是否有允许我

的Python函数
  • 迭代(有序)对象列表
  • 内部存储绝对值
  • 读取每个对象的更改,更新内部绝对值
  • 用绝对值替换相对变化

2 个答案:

答案 0 :(得分:2)

以下是如何使用列表解析执行此操作:

>>> data = [(+1,0), (-1, 1), (+1,3), (+1, 3), (-1, 5), (+1, 9)]
>>> [(sum(x[0] for x in data[:i+1]), data[i][1]) for i in range(len(data))]
[(1, 0), (0, 1), (1, 3), (2, 3), (1, 5), (2, 9)]

或稍微更高效(不会为每个值调用sum()):

result = [data[0]]
for change, t in data[1:]:
    result.append((result[-1][0]+change, t))

由于您说这些是对象,因此您可能需要使用属性get替换索引,例如x[0]中的sum(x[0] for x in data[:i+1])可能会变为x.change

答案 1 :(得分:0)

可以使用列表理解来做这件事,但考虑到你的请求的具体条款,这对我来说似乎更像是一个生成器的工作。这是一个非常通用的解决方案,应该适用于序列和迭代器。它在传递给它的iterable上执行相当于Haskell的scanl函数,并将可选的初始值作为最后一个参数。

第一个参数应该是一个带有两个参数的函数 - 当前的累积状态和序列中的下一个项 - 并返回下一个累积状态。它可以像operator.add一样简单,也可以更复杂。

>>> def scan(f, seq, init=None):
...     seq = iter(seq)
...     state = seq.next() if init is None else init
...     yield state
...     for i in seq:
...         state = f(state, i)
...         yield state

累计求和(即三角数):

>>> import operator
>>> list(scan(operator.add, range(10)))
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]

以不同的初始值开头:

>>> list(scan(operator.add, range(1, 10), 10))
[10, 11, 13, 16, 20, 25, 31, 38, 46, 55]

适用于您的问题:

>>> diffs = [(1, 0), (-1, 1), (1, 3), (1, 3), (-1, 5), (1, 9)]
>>> list(scan(lambda x, y: (x[0] + y[0], y[1]), diffs))
[(1, 0), (0, 1), (1, 3), (2, 3), (1, 5), (2, 9)]

具有不同的初始值,只是为了它的乐趣。

>>> list(scan(lambda x, y: (x[0] + y[0], y[1]), diffs, (5, -1)))
[(5, -1), (6, 0), (5, 1), (6, 3), (7, 3), (6, 5), (7, 9)]