拆分列表并从子列表中进行求和?

m4r*_*cek 5 int haskell numbers

我正在寻找我的Haskell类的解决方案.

我有一个数字列表,我需要为列表的每个部分返回SUM.零件除以0.我需要使用FOLDL功能.

示例:
初始列表:[1,2,3,0,3,4,0,5,2,1]
子列表[[1,2,3],[3,4],[5,2,1]]
结果[6,7,7]

我有一个在初始列表中找到0的函数:

findPos list = [index+1 | (index, e) <- zip [0..] list, e == 0] 
Run Code Online (Sandbox Code Playgroud)

(从示例中返回[4,6]作为初始列表)

和用FOLDL制作SUM的功能:

sumList list = foldl (+) 0 list
Run Code Online (Sandbox Code Playgroud)

但我完全没能把它放在一起:/

----我的解决方案
最后,我发现了一些与你们建议完全不同的东西.
花了我一整天才成功:/

groups :: [Int] -> [Int]
groups list = [sum x | x <- makelist list]

makelist :: [Int] -> [[Int]]
makelist xs = reverse (foldl (\acc x -> zero x acc) [[]] xs)  

zero :: Int -> [[Int]] -> [[Int]]
zero x acc | x == 0 = addnewtolist acc
           | otherwise = addtolist x acc

addtolist :: Int -> [[Int]] -> [[Int]]
addtolist i listlist = (i : (head listlist)) : (drop 1 listlist)

addnewtolist :: [[Int]] -> [[Int]]
addnewtolist listlist = [] : listlist
Run Code Online (Sandbox Code Playgroud)

Dan*_*ner 6

我将给你一些提示,而不是一个完整的解决方案,因为这听起来像是一个家庭作业.

我喜欢你建议的步骤细分.对于第一步(从具有零标记的数字列表到列表列表),我建议进行显式递归; 试试这个模板:

splits []     = {- ... -}
splits (0:xs) = {- ... -}
splits (x:xs) = {- ... -}
Run Code Online (Sandbox Code Playgroud)

groupBy如果你小心的话,你也可以滥用.

第二步,看起来你几乎就在那里; 你需要的最后一步是看看map :: (a -> b) -> ([a] -> [b])函数,它接受一个普通函数并在列表的每个元素上运行它.

作为一项奖励练习,您可能想要考虑如何在一次性完成整个过程中作为单一折叠.如果你追踪到foldr/ foldl将要包含的各种参数的类型,这是可能的 - 甚至不是太困难!

自问题改变以来的补充:

既然看起来你已经找到了解决方案,我现在觉得很舒服一些剧透.=)

我提出了两个可能的实现 正如你所建议的那样,一步一步地进行,另一种是一次又一次.一步一步可能如下所示:

splits []     = []
splits (0:xs) = [] : splits xs
splits (x:xs) = case splits xs of
    []       -> [[x]]
    (ys:yss) -> ((x:ys):yss)

groups' = map sum . splits
Run Code Online (Sandbox Code Playgroud)

或者像这样:

splits' = groupBy (\x y -> y /= 0)
groups'' = map sum . splits'
Run Code Online (Sandbox Code Playgroud)

一次性版本可能如下所示:

accumulate 0 xs     = 0:xs
accumulate n (x:xs) = (n+x):xs

groups''' = foldr accumulate [0]
Run Code Online (Sandbox Code Playgroud)

要检查您是否理解这些,您可以尝试以下几种练习:

  • 做什么splitssplits'[1,2,3,0,4,5]什么?[1,2,0,3,4,0][0][]?检查你在ghci的预测.
  • 预测什么四个版本的groups(包括你)输出输入等[][1,2,0,3,4,0],然后测试在ghci中的预测.
  • 修改groups'''以展示其他实现之一的行为.
  • 修改groups'''使用foldl而不是foldr.


D. *_*aum 2

现在您已经自己完成了该问题,我将向您展示一个稍微不那么冗长的版本。 Foldr在我看来,这个问题似乎更好*,但因为你要求,foldl我将向你展示我使用这两个函数的解决方案。

另外,你的例子似乎不正确,[5,2,1]的总和是8,而不是7。

版本foldr

makelist' l = foldr (\x (n:ns) -> if x == 0 then 0:(n:ns) else (x + n):ns) [0] l
Run Code Online (Sandbox Code Playgroud)

在这个版本中,我们遍历列表,如果当前元素(x)是0,我们将一个新元素添加到累加器列表(n:ns)。否则,我们将当前元素的值添加到累加器前面元素的值中,并用该值替换累加器前面的值。

一步步:

  1. acc = [0], x = 1. Result is [0+1]
  2. acc = [1], x = 2. Result is [1+2]
  3. acc = [3], x = 5. Result is [3+5]
  4. acc = [8], x = 0. Result is 0:[8]
  5. acc = [0,8], x = 4. Result is [0+4,8]
  6. acc = [4,8], x = 3. Result is [4+3,8]
  7. acc = [7,8], x = 0. Result is 0:[7,8]
  8. acc = [0,7,8], x = 3. Result is [0+3,7,8]
  9. acc = [3,7,8], x = 2. Result is [3+2,7,8]
  10. acc = [5,7,8], x = 1. Result is [5+1,7,8] = [6,7,8]

你有它!

还有foldl版本。工作原理与上面类似,但会产生一个反转列表,因此在此函数的开头使用reverse来取消反转列表。

makelist l = reverse $ foldl (\(n:ns) x -> if x == 0 then 0:(n:ns) else (x + n):ns) [0] l
Run Code Online (Sandbox Code Playgroud)

*从右侧折叠列表可以自然地使用 cons (:) 函数,使用我的方法与左侧折叠会产生一个反向列表。(可能有一种更简单的方法来完成我没有想到的左折叠版本,从而消除了这种琐碎的事情。)