1

可能重复:
拆分列表并从子列表中求和?

我试图解决这个问题。我需要对列表中的元素进行总和,这些元素仅用“0”相互分隔。例如,我可以有这样的输入:[1,2,3,0,3,4,0,2,1],输出应该是 [6,7,3]。

到目前为止,我设法做这样的事情:

cut (x:xs) | x > 0 = x : (cut xs)
       | otherwise = []

first  (xs) = ( (foldl (+) 0 (cut          (xs)))   ) : []
second (xs) = ( (foldl (+) 0 (cut (reverse (xs))))  ) : []

test (xs) = first(xs) ++ second(xs)

问题是这只适用于我的列表中只有 1 个“0”实例。

我试图通过编辑我的剪切功能来解决这个问题:

cut [] = []
cut (x:xs) | x > 0 = foldl (+) 0 ( x : cut xs) : []
       | x == 0 = (cut xs)

但我不知道如何调整它,所以它会将总和分开。现在它只是将所有元素的总和作为输出。

4

3 回答 3

5

你可以把你的问题分成两个任务

  1. 将列表拆分为零部分。
  2. 总结部分。

对于第一个任务,我们有Data.List.Split导出splitOn函数的模块。它正是我们需要的:

> splitOn [1] [0,0,0,1,0,0,0,1,0]
[[0,0,0],[0,0,0],[0]]

对于第二个任务,有众所周知的map-function 将函数应用于列表的每个元素。在我们的例子中,这个函数是sum

> map sum [[1,2,3],[4,5,6],[7,8,9]]
[6,15,24]

所以:

> :m +Data.List.Split
> map sum . splitOn [0] $ [1,2,3,0,3,4,0,2,1] 
[6,7,3]
于 2012-04-07T17:42:19.200 回答
1

即使您无法按照 Matvey 的建议安装拆分包并使用 Data.List.Split,您仍然可以使用一般方法:

  1. 将带有分隔符的怪异列表拆分0为更常规的列表列表。
  2. 对每个列表求和。

所以

yourFunction = map sum . split

现在我们必须编写split.

split :: [Int] -> [[Int]]

一般来说,当我们想把一个列表拉开来合成一些新的东西时,我们需要使用折叠。

split = foldr cons nil where

nil这里应该是你想成为的任何东西split []

    nil = --TODO: exercise for you; clue: NOT []

cons同时将您的一个数字与折叠的上一步的答案结合起来。显然,您需要根据数字是否为0.

    cons 0 xss        = --TODO
    cons x (xs : xss) = --TODO; why will this pattern match never fail?
于 2012-04-07T18:01:41.083 回答
1

对于家庭作业,您绝对应该遵循戴夫的回答。然而,这里有一个更高级的解决方案,使用groupBy作为穷人的split

import Data.List (groupBy)

map sum $ groupBy (const (/=0)) list

这可能看起来很可爱,但请注意,在子列表的开头仍然存在零,因此如果这很重要(例如,如果您需要产品而不是总和),您不能在不更改的情况下使用此解决方案

[解释]

groupBy查看当前组的第一个元素是否与列表的当前元素“组合在一起”。在这种情况下,当前元素将被添加到组中,否则将启动一个新组。例如

groupBy (\x y -> x `mod` y == 0) [81,3,9,25,5]
--[[81,3,9],[25,5]]

这里测试成功81 'mod' 381 'mod' 9,但不成功81 'mod' 25,它开始了一个新组。再次,25 'mod' 5是成功的。

但在我们的例子中,只要不为 0,所有元素都“适合”当前组,因此我们甚至不必查看第一个元素。如果找到 0,则开始一个新组。

const (/=0)表示 just \_ y -> y /= 0,所以不管第一个参数是什么,它只是测试第二个元素不为 0。要了解原因,请查看定义:

const :: a -> b -> a
const a _ =  a

现在我们的 lambda 可以写成

\x y -> const (/= 0) x y

由于从const调用中只有两个参数中的第一个“存活”,我们有

\x y -> (/= 0) y

... 或者...

\_ y -> y /= 0
于 2012-04-08T08:25:03.113 回答