我有一个如下所示的列表:
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中实现此功能。具体来说,如何遍历列表,并删除一个元素,但每次将删除的值增加一。有人可以帮忙吗?谢谢。我一直在尝试编写一个使用折叠的辅助函数,但我无法弄清楚如何在每次“迭代”时从最后一个元素中删除不同的元素。
答案 0 :(得分:12)
你可以写下这些内容:
f xss@(x:xs) = total : map (total -) xs
where total = sum xss
基本上它说首先你有你的列表的总和,然后你对每个元素都有这个相同的总和减去这个元素(我们跳过头)。
更多详情:
(x:xs)
用于对给定列表进行模式匹配,以便稍后我们只需使用xs
xss@...
用于命名整个模式,以便我们仍然可以轻松使用整个列表(total -)
是一个运算符部分:当使用参数x
调用时,它将返回total - x
注意:您必须确定当此函数被赋予空列表时会发生什么,例如,如果您希望它返回空列表,请添加:
f [] = []
修改:关于map (total -) xs
的解释:
正如我在上面的列表中详述的那样,(total -)
是一个操作符部分,它为我们提供了以下功能:
\x -> total - x
它返回总减去它给出的值。
现在,我们将该函数映射到给予f
的列表的尾部。例如,如果您提供f
列表
[1, 2, 6, 3, 9]
我将映射到
[2, 6, 3, 9]
如果总计为21
,则地图调用的结果为
[19, 15, 18, 12] -- [21 - 2, 21 - 6, 21 - 3, 21 - 9]
答案 1 :(得分:9)
Mog给出了一个答案,它利用(+)
是关联的,可交换的,并且具有逆的事实。但是,我认为给出适用于任何操作的答案也是有建设性的;也就是说,为了产生你正在求和的实际列表,然后求它们。所以计划将是这样的:
Prelude
中完成:使用sum
函数)。有几种方法可以完成第一部分。第一个选择是显式递归:
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
模块包含一系列用于以特定方式对列表进行修改的函数。其中两个是tails
和inits
:
*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]