Functional programming 在函数式语言中,如何有条件地选择要在zip或zipWith样式函数中使用的元素?

Functional programming 在函数式语言中,如何有条件地选择要在zip或zipWith样式函数中使用的元素?,functional-programming,conditional-operator,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))} from operator import div def av

我熟悉在两个序列的对应元素上操作的标准zipWith函数,但在函数语言或具有某些函数特性的语言中,基于第三个序列有条件地选择要压缩的元素对的最简洁的方法是什么

这种好奇心是在用Excel抓取一些东西时产生的。 对于A1:A10、B1:B10、C1:C10、D1、E1和F1中的数字,我使用的公式如下:

{=AVERAGE(IF((D1<=(A1:A10))*((A1:A10)<=E1),B1:B10/C1:C10))}
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])
AVERAGE函数碰巧忽略了布尔值和文本值,所以我们只得到第二个和第三个商的平均值

哈斯克尔能做到这一点吗?二郎?林克还是F?python等等

请注意,对于这个特定的例子,上面给出的公式并不完全正确,它被简化以获得基本点。当A1:A10中的十个元素都不满足条件时,十个假值将传递给AVERAGE,这将错误地计算为0。 公式应按以下方式编写:

{=AVERAGE(IF(NOT(OR((D1<=(A1:A10))*((A1:A10)<=E1))),NA(),
             IF((D1<=(A1:A10))*((A1:A10)<=E1),B1:B10/C1:C10)))}
更一般地说,对于函数f和谓词p以及avg,这将变成:

avg([f(t[1:]) for t in zip(*nums) if p(t[0])])
哈斯克尔:

average . map fromJust . filter isJust $ zipWith3 (\a b c -> if a >= d1 && a <= e1 then Just b/c else Nothing) as bs cs
  where average xs = let (sum,n) = foldl' (\(s,m) x -> (s+x,m+1)) (0,0) xs in sum / (fromIntegral n)

你要找的是。特别是链接纸上的快速应用程序

在Haskell表示法中,我们调用函数f。然后,使用应用程序编程,它将简洁如下:

f d e as bs cs = if' <$> ((&&) <$> (d <=) <*> (e >=))
                     <$> as <*> ((/) <$> bs <*> cs) <*> (repeat 0)
   where if' x y z = if x then y else z
         (<*>)     = zipWith ($)
这里,p是一个谓词,因此您可以用以下形式调用它:

average $ fromMaybe 0 <$> f (/) ((&&) <$> (d <=) <*> (e >=)) as bs cs
。。。给出与上述相同的定义

注意:我还没有测试这段代码,所以可能会缺少括号之类的东西,但这让我明白了这一点

如何在zip中有条件地选择元素

先压缩,后选择

在本例中,我使用catMaybes进行选择,wihch在该设置中通常很有用。要进行类型检查是一个巨大的痛苦,必须将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)
函数cdiv代表条件除法

要获取catMaybes,您必须导入数据


这段代码会进行类型检查,但我还没有运行它。

好的,很酷。那么您定义的平均函数将忽略Nothing值?如果原来的公式恰好是{=AverageIfd1如果不会,这可能甚至不会进行类型检查…您可以将第一行更改为average.map fromJust.filter只是$…,这将删除所有Nothing值并展开其他值。zipWith函数的定义一直到zipWith7,但您可以为更高阶的函数编写自己的。由于Haskell的严格类型system不可能创建一个通用的zipWith函数。哇,这太激烈了。我想我明白了,就zip如何反复应用来执行转置而言。这实际上是我最初应该问的问题的答案,即zipWith函数是否不仅可以有条件地应用,而且可以在任意条件下应用列表/向量的数量。感谢应用程序的提示,这就是我现在要使用的解决方案。请参见上面的更新。谢谢,是的,这是我最初编写问题时考虑的方法。但请参见上面Apocalisp和我的更新的答案。
average $ fromMaybe 0 <$> f (/) ((&&) <$> (d <=) <*> (e >=)) as bs cs
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)