如何遍历列表并逐步删除值

时间:2012-09-02 20:06:17

标签: haskell

我有一个如下所示的列表:

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中实现此功能。具体来说,如何遍历列表,并删除一个元素,但每次将删除的值增加一。有人可以帮忙吗?谢谢。我一直在尝试编写一个使用折叠的辅助函数,但我无法弄清楚如何在每次“迭代”时从最后一个元素中删除不同的元素。

2 个答案:

答案 0 :(得分: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]

如果总计为21,则地图调用的结果为

[19, 15, 18, 12] -- [21 - 2, 21 - 6, 21 - 3, 21 - 9]

答案 1 :(得分:9)

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

  1. 编写一个在每个可能位置拆分列表的函数。
  2. 编写一个函数,通过在拆分处删除元素,将拆分转换回列表。
  3. 编写一个汇总列表的函数(已在Prelude中完成:使用sum函数)。
  4. 编写一个组合它们的函数,并包含整个列表的特殊情况。
  5. 有几种方法可以完成第一部分。第一个选择是显式递归:

    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]