2

我有一个看起来像这样的列表:

lst = [1,2,6,3,9]

我想编写一个函数,将列表中的所有数字相加并将该值附加到一个新列表中,然后遍历列表并逐个删除一个值并对这些值求和。该函数将执行此计算:

result = [[1+2+6+3+9],
          [1+6+3+9],
          [1+2+3+9],
          [1+2+6+9],
          [1+2+6+3]]

鉴于上面的列表示例,我试图描述的函数将产生此结果:

[21,19,15,18,12]

我很难理解如何在 Haskell 中实现这个功能。具体来说,如何遍历一个列表,并删除一个元素,但每次将删除的值加一。任何人都可以帮忙吗?谢谢。我一直在尝试编写一个使用折叠的辅助函数,但我不知道如何在每次“迭代”时从最后一个元素中删除一个不同的元素。

4

2 回答 2

12

你可以按照这些思路写一些东西:

f xss@(x:xs) = total : map (total -) xs
  where total = sum xss

基本上它说首先你有你的列表的总和,然后你对于每个元素都有这个相同的总和减去这个元素(我们跳过头部)。

更多细节:

  • (x:xs)用于在给定列表上进行模式匹配,以便我们稍后只需使用即可轻松跳过头部xs
  • xss@...用于命名整个模式,以便我们仍然可以轻松使用整个列表
  • where 子句引入了一个保存列表总和的变量,这样它就不会被重新计算很多次(也许它已经被优化了,我们确信这样)。
  • (total -)是一个操作符部分:当使用参数调用时x,它会返回total - x

注意:当这个函数被给定一个空列表时,你必须精确说明会发生什么,例如,如果你希望它返回空列表,添加:

f [] = []

编辑:关于的解释map (total -) xs

正如我在上面的列表中详述的那样,(total -)是一个运算符部分,它为我们提供了以下功能:

\x -> total - x

它返回总数减去它给出的值。

现在,我们将该函数映射到给定列表的尾部f。例如,如果您给出f列表

[1, 2, 6, 3, 9]

它会让我映射过来

[2, 6, 3, 9]

如果 total 是21,则 map 调用的结果是

[19, 15, 18, 12] -- [21 - 2, 21 - 6, 21 - 3, 21 - 9]
于 2012-09-02T20:36:13.967 回答
9

(+)Mog 给出了一个答案,它利用了关联、交换和逆的事实。但是,我认为给出一个适用于任何操作的答案也是建设性的;也就是说,要生成要求和的实际列表,然后将它们求和。所以计划会是这样的:

  1. 编写一个在每个可能位置拆分列表的函数。
  2. 编写一个函数,通过在拆分处删除元素将拆分回列表。
  3. 编写一个对列表求和的函数(已经完成Prelude:使用该sum函数)。
  4. 编写一个函数来组合它们,并包含整个列表的特殊情况。

第一部分有几种方法。第一种选择是显式递归:

splits :: [a] -> [([a], [a])]
splits []     = [([],[])]
splits (x:xs) = ([],x:xs) : map (\(b,e) -> (x:b,e)) (splits xs)

我们可以在 ghci 中检查它以确保我们做对了:

*Main> splits "abcde"
[("","abcde"),("a","bcde"),("ab","cde"),("abc","de"),("abcd","e"),("abcde","")]

但是,有一个更好的方法。该Data.List模块包含一系列用于以特定方式修改列表的功能。其中两个是tailsinits

*Main> tails "abcde"
["abcde","bcde","cde","de","e",""]
*Main> inits "abcde"
["","a","ab","abc","abcd","abcde"]

所以这个定义看起来更好看:

splits xs = zip (inits xs) (tails xs)

现在,我们需要一个函数来生成列表列表,其中每个位置删除一个元素。

dropEach xs = [beginning ++ end | (beginning, ignored:end) <- splits xs]

所以最后一步是将所有东西放在一起。

funnySums xs = map sum (xs : dropEach xs)

我们可以测试:

*Main> funnySums [1, 10, 100, 1000, 10000]
[11111,11110,11101,11011,10111,1111]
于 2012-09-02T21:19:12.943 回答