当列表项依赖于较早的项目时使用函数形式
Using functional form when list item is dependent on earlier items
我有元组列表,每个元组都有元素长度。我使用以下代码根据早期元素的长度计算元素的偏移量。
import pprint
recordInfo = [(3,), (4,), (1,), (2,)] # List of lengths
# Calculate and add offsets
recordSize = 0
for index, info in enumerate(recordInfo):
recordInfo[index] = info + ( recordSize, ) # Replace with new tuple with offset
recordSize += info[0] # Calculate next offset
pprint.pprint(recordInfo)
输出为
[(3, 0), (4, 3), (1, 7), (2, 8)]
有没有办法以函数形式执行循环,例如列表理解?我不知道如何避免临时变量 recordSize
,这使得它不可能?
可能不是你所说的功能性但嘿,总是很有趣。
def increment_record(records, size=0):
if not records:
return []
return [(records[0], size)] + increment_record(records[1:], size=size+records[0])
但是,是的,我不认为这真的是一种模式 python 允许一个人在没有本地状态的情况下进行寻址(当然除非你使用像前面提到的高级功能 itertools.aggregate 只是隐藏了状态)。当然,如果你真的需要,你可以只定义某种计数对象(或使用闭包)。
class Tallier(object):
def __init__(self, val):
self._val = val
def tally(self, new_val):
old_val = self._val
self._val += new_val
return old_val
[(val, tallier.tally(val)) for val in values]
它不漂亮,而且效率不高,但这是一个列表理解,可以满足您的要求:
>>> recordInfo = [(3,), (4,), (1,), (2,)]
>>> [info + (sum(_info[0] for _info in recordInfo[:i]),)
for i,info in enumerate(recordInfo)]
[(3, 0), (4, 3), (1, 7), (2, 8)]
它的工作原理是在每次迭代时重新计算到当前项目的偏移量,因此效率很低。
它适用于 Python 2 和 3。
>>> recordInfo = [3, 4, 1, 2]
>>> from functools import reduce
>>> reduce(lambda x, y: x + [(y, sum(x[-1]))], recordInfo, [(0, 0)])[1:]
[(3, 0), (4, 3), (1, 7), (2, 8)]
>>> from itertools import accumulate
>>> list(zip(recordInfo, [0] + list(accumulate(recordInfo))))
[(3, 0), (4, 3), (1, 7), (2, 8)]
如果你有元组:
>>> recordInfo = [(3, 'a'), (4, 'b'), (1, 'c'), (2, 'd')]
>>> reduce(lambda x, y: x + [y + (x[-1][0] + x[-1][-1], )], recordInfo, [(0, )])[1:]
[(3, 'a', 0), (4, 'b', 3), (1, 'c', 7), (2, 'd', 8)]
>>> from operator import itemgetter
>>> [x + (c,) for x, c in zip(recordInfo, accumulate(map(itemgetter(0), [(0,)] + recordInfo)))]
[(3, 'a', 0), (4, 'b', 3), (1, 'c', 7), (2, 'd', 8)]
我有元组列表,每个元组都有元素长度。我使用以下代码根据早期元素的长度计算元素的偏移量。
import pprint
recordInfo = [(3,), (4,), (1,), (2,)] # List of lengths
# Calculate and add offsets
recordSize = 0
for index, info in enumerate(recordInfo):
recordInfo[index] = info + ( recordSize, ) # Replace with new tuple with offset
recordSize += info[0] # Calculate next offset
pprint.pprint(recordInfo)
输出为
[(3, 0), (4, 3), (1, 7), (2, 8)]
有没有办法以函数形式执行循环,例如列表理解?我不知道如何避免临时变量 recordSize
,这使得它不可能?
可能不是你所说的功能性但嘿,总是很有趣。
def increment_record(records, size=0):
if not records:
return []
return [(records[0], size)] + increment_record(records[1:], size=size+records[0])
但是,是的,我不认为这真的是一种模式 python 允许一个人在没有本地状态的情况下进行寻址(当然除非你使用像前面提到的高级功能 itertools.aggregate 只是隐藏了状态)。当然,如果你真的需要,你可以只定义某种计数对象(或使用闭包)。
class Tallier(object):
def __init__(self, val):
self._val = val
def tally(self, new_val):
old_val = self._val
self._val += new_val
return old_val
[(val, tallier.tally(val)) for val in values]
它不漂亮,而且效率不高,但这是一个列表理解,可以满足您的要求:
>>> recordInfo = [(3,), (4,), (1,), (2,)]
>>> [info + (sum(_info[0] for _info in recordInfo[:i]),)
for i,info in enumerate(recordInfo)]
[(3, 0), (4, 3), (1, 7), (2, 8)]
它的工作原理是在每次迭代时重新计算到当前项目的偏移量,因此效率很低。
它适用于 Python 2 和 3。
>>> recordInfo = [3, 4, 1, 2]
>>> from functools import reduce
>>> reduce(lambda x, y: x + [(y, sum(x[-1]))], recordInfo, [(0, 0)])[1:]
[(3, 0), (4, 3), (1, 7), (2, 8)]
>>> from itertools import accumulate
>>> list(zip(recordInfo, [0] + list(accumulate(recordInfo))))
[(3, 0), (4, 3), (1, 7), (2, 8)]
如果你有元组:
>>> recordInfo = [(3, 'a'), (4, 'b'), (1, 'c'), (2, 'd')]
>>> reduce(lambda x, y: x + [y + (x[-1][0] + x[-1][-1], )], recordInfo, [(0, )])[1:]
[(3, 'a', 0), (4, 'b', 3), (1, 'c', 7), (2, 'd', 8)]
>>> from operator import itemgetter
>>> [x + (c,) for x, c in zip(recordInfo, accumulate(map(itemgetter(0), [(0,)] + recordInfo)))]
[(3, 'a', 0), (4, 'b', 3), (1, 'c', 7), (2, 'd', 8)]