Dav*_*ave 5 functional-programming conditional-operator
我熟悉zipWith对两个序列的相应元素进行操作的标准函数,但是在函数式语言(或具有某些功能特性的语言)中,有条件地选择要压缩的元素对的最简洁方法是什么,基于第三顺序?
这种好奇心是在Excel中剔除一些东西时产生的.
A1中有数字:A10,B1:B10,C1:C10,D1,E1和F1,我使用的公式如下:
{=AVERAGE(IF((D1<=(A1:A10))*((A1:A10)<=E1),B1:B10/C1:C10))}
Run Code Online (Sandbox Code Playgroud)
IF语句中乘法的每一半都将产生一个布尔值数组,然后将它们相乘(和).那些布尔人控制十个商中的哪一个最终将被平均,所以就好像正在评估10个单独的IF语句.
例如,如果A1:A10中的10个值中只有第二个和第三个满足条件(> = D1和<= E1),那么公式最终会得到评估:
AVERAGE(FALSE,B2/C2,B3/C3,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE)
Run Code Online (Sandbox Code Playgroud)
AVERAGE函数碰巧忽略了布尔值和文本值,所以我们只得到第二和第三商的平均值.
这可以用Haskell简洁地完成吗?二郎?LINQ还是F#?蟒蛇?等等..
请注意,对于此特定示例,上面给出的公式并不完全正确 - 它缩写为获得基本点.当A1:A10中的十个元素都不满足条件时,则将十个FALSE值传递给AVERAGE,这将错误地计算为0.
公式应该这样写:
{=AVERAGE(IF(NOT(OR((D1<=(A1:A10))*((A1:A10)<=E1))),NA(),
IF((D1<=(A1:A10))*((A1:A10)<=E1),B1:B10/C1:C10)))}
Run Code Online (Sandbox Code Playgroud)
当NA()产生一个错误,这表明平均是未定义的.
谢谢你的回答.我意识到,当第一个列表中的相应元素符合某些特定条件时,在第二个和第三个列表中对元素对应用函数时,我的第一个问题非常简单.我接受了Norman Ramsey的答案.
然而,我去的下一步是想知道该函数是否可以应用于表示来自任意数量列表的相应元素的元组 - 因此我向Lebertram提出了关于限制的问题zipWithN.
Apocalisp关于applicative functor的信息让我了解了python对参数列表的解包 - 将函数应用于任意数量的参数.
对于我上面给出的具体示例,平均列表元素的商(其中nums是列表列表),看起来像python可以这样做:
from operator import div
def avg(a): return sum(a,0.0)/len(a)
avg([reduce(div,t[1:]) for t in zip(*nums) if d<=t[0] and t[0]<=e])
Run Code Online (Sandbox Code Playgroud)
更一般地说,使用函数f和谓词p(以及avg),这将成为:
avg([f(t[1:]) for t in zip(*nums) if p(t[0])])
Run Code Online (Sandbox Code Playgroud)
如何有条件地选择zip中的元素?
先压缩,然后选择。
在本例中,我使用 , 进行选择catMaybes,这在此设置中通常很有用。进行类型检查是一个巨大的痛苦(必须放在fromIntegral正确的位置),但这是我要编写的代码,像往常一样依赖优化器:
average as bs cs d1 e1 = avg $ catMaybes $ zipWith3 cdiv as bs cs
where cdiv a b c = if a >= d1 && a <= e1 then Just (b/c) else Nothing
avg l = sum l / fromIntegral (length l)
Run Code Online (Sandbox Code Playgroud)
函数cdiv代表“条件除法”。
为了得到catMaybes你必须导入Data.Maybe。
这段代码进行了类型检查,但我还没有运行它。