肾盂累积图

2024-06-16 11:35:14 发布

您现在位置:Python中文网/ 问答频道 /正文

有没有一种更像Python的方法来做以下事情:

def mysteryFunction( it, fun, val ):
    out = []
    for x in it:
        y,val = fun(x,val)
        out.append(y)
    return out,val

其中it是iterable,fun是一个接受两个输入并返回两个输出的函数,val是一个初始值,它通过每次调用fun进行“转换”?你知道吗

我之所以问这个问题是因为我经常使用map, zip, filter, reduce和列表理解,但是我不能将前面的函数表示为这些函数的组合,现在已经出现了好几次了。是我遗漏了一个隐藏的习语,还是这个习语太过利基而配不上一个?你知道吗


一个具体的例子是从一定的秒数开始计算(年、周、日、时、分、秒)的持续时间:

fac = (365*24*3600, 7*24*3600, 24*3600, 3600, 60, 1)
dur,rem = mysteryFunction( fac, lambda x,y: divmod(y,x), 234567 )

其中dur是持续时间元组,rem对应于最后的余数(此处为零或十进制,具体取决于初始值的类型)。这不仅仅是精心挑选的,还有许多其他的例子,例如:积分微分方程的固定步长方法(迭代步长、步进函数、初始状态);模拟有界随机游走;无递归的跨深度树处理;等等


Tags: 方法函数itvalout事情例子持续时间
1条回答
网友
1楼 · 发布于 2024-06-16 11:35:14

这种结构类似于the ^{} generator function的设计目的。例如,您的函数可能与以下函数一起使用:

def add2(x, y):
    return (x + y,) * 2 # Returning the same thing twice, new sum and accumulate sum the same

然后打电话给:

mysteryFunction(range(5), add2, 0)

它将返回:

([0, 1, 3, 6, 10], 10)

从0到4的累计和,以及最终的和。你知道吗

itertools.accumulate可以做同样的事情,但它是懒惰的(它根据请求返回每个累积值),并且只对单个输出函数的两个操作数起作用;对于这种情况,它最终变得更简单:

from itertools import accumulate
from operator import add

list(accumulate(range(5), add))

将产生与mystery_function相同的list(第二个结果只是list的最后一个值),但是您也可以延迟使用它,而不将结果存储在list中,例如:

for partialsum in accumulate(range(5), add):
    ... do stuff with partialsum ...

您可能会通过accumulate来处理双输入双输出函数(或者更准确地说,从accumulate输出的值中丢弃您不关心的值),但大多数情况下,我希望第二个输出是迄今为止的累积值,而不是真正分开的,因此避免第二个输出会更干净。你知道吗

为了好玩,一种可怕的按摩你的结构来匹配accumulate。假设您想向输入中的每个元素添加一个base值,但是每次将base减少1。对于函数,您将执行(对于10的初始值base):

def addless(new, base):
    return base + new, base - 1

mysteryFunction(range(5), addless, 10)

它(由于传递了range,抵消了base的每次减少)产生了([10, 10, 10, 10, 10], 5)。与accumulate类似的代码可能是:

def addless2(last_base, new):
    _, base = last_base
    return base + new, base - 1

然后(因为不能直接为accumulate指定初始值,所以有些丑陋):

from itertools import accumulate, chain

base = 10

# chain used to provide initial value
accum = accumulate(chain(((None, base),), range(5)), addless2)

next(accum)   # Throw away first value that exists solely to make initial tuple

# Put the first value from each `tuple` in `out`, and keep the second value
# only for the last output, to preserve the final base
out, (*_, base) = zip(*accum)

这使得vals变成了(10, 10, 10, 10, 10)base变成了5,就像在你的代码中一样(为这个魔术道歉;zip使用通用的嵌套解包,既漂亮又恐怖)。你知道吗

相关问题 更多 >