【问题标题】:Function that returns a weighted average from a list of lists of numbers从数字列表中返回加权平均值的函数
【发布时间】:2021-12-22 09:01:09
【问题描述】:

编写weightedAverage :: [[Int]] -> Double 函数,计算成绩的加权平均值。

例如:

weightedAverage [[3], [5]] == 4.0

weightedAverage [[3,3], [5,5]] == 4.0

weightedAverage [[1,5], [5,5]] == 4.0

weightedAverage [[3,3,3,3], [5,5], [5,5]] == 4.0

到目前为止,我设法编写了一个返回列表平均值的函数:

listAverage :: [Int] -> Double
listAverage [] = 0.0
listAverage x = fromIntegral(sum x)/fromIntegral(length x)

我想在我的weightedAverage 函数中使用以下代码实现这一点:

weightedAverage [[]] = 0.0
weightedAverage [x] = listAverage x
weightedAverage (x:xs) = (listAverage x + weightedAverage (xs))/fromIntegral length(x:xs)

问题是我得到一个Ambiguous type variable 't0' arising from a use of 'length' 错误以及一个No instance for (Integral (t0 a0 -> Int)) arising from a use of 'fromIntegral' 错误。我也认为我的递归没有正确实现。

【问题讨论】:

  • 提示:连接列表中的项目。
  • / 谁是设计这些绝对密集示例的滥用者? / Haskell 中的函数调用语法是(foo arg),而不是arg(foo)
  • 关于您的主题,请参阅en.wikipedia.org/wiki/Weighted_arithmetic_mean

标签: haskell recursion average


【解决方案1】:

列表的权重是项目的数量。因此,这意味着我们可以简单地连接列表列表,然后确定平均值,因此您可以通过以下方式实现:

weightedAverage :: [[Int]] -> Double
weightedAverage = listAverage . 

其中 是一个函数:: [[a]] -> [a],它将项目列表转换为这些项目的列表。

至于listAverge,使用两个分别跟踪总和和长度的累加器可能更有意义,例如:

listAverage :: [Int] -> Double
listAverage = go (0 :: Integer) (0 :: Word) . map toInteger
  where go !s !n [] = fromRational (s % toInteger n)
        go s n (x:xs) = …

【讨论】:

  • 感谢您的帮助。作为记录:我用(concat (x:xs)) 代替了...
  • @CoderStudent8822:请不要使用(x:xs):这仅适用于非空列表。您可以使用weightedAverage xs = listAverage (concat xs) 进行模式匹配,或者简单地使用weightedAverage = listAverage . concat
  • 在这种特定的情况下,冗余模式匹配在语义上是可以的,因为它只是用不完整的模式错误替换了除以零错误。但由于技术原因,它也会使代码效率降低。再说一次,这个特定的代码已经非常低效了,所以这可能无关紧要。
  • 我会使用listAverage = go (0 :: Integer) (0 :: Word) . map toInteger。这将消除长度最多为maxBound :: Word 的列表的溢出风险(您可以使用Data.Word.Word64 更加自信)。为避免因大数而损失精度,最好写go !s !n [] = fromRational (s % toInteger n)
  • @dfeuer 任务的明显意图是使用权重实际执行weighted average calculation,而不仅仅是通过不同的方式计算相同的结果。如果这样做了,精度损失和溢出风险就会大大降低,并且在新手练习中效率问题是第三个问题,因此可以使用Integer
猜你喜欢
  • 2021-12-20
  • 1970-01-01
  • 2013-04-21
  • 2021-02-08
  • 2019-12-14
  • 2019-03-15
  • 2018-02-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多