2012-04-07 67 views
1

可能重复:
Split list and make sum from sublist?总和分隔的元素

我试着去解决这个问题。 我需要做一个列表中的元素的总和,这些元素只能用“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) 

但我无法弄清楚如何调整它,所以它会分开的款项。现在它只是抛出所有元素的总和作为输出。

回答

1

要完成作业,您一定要关注戴夫的回答。然而,这里是一个更先进的解决方案,采用groupBy作为穷人的split

import Data.List (groupBy) 

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

这可能看起来很可爱,但要注意,还有目前子列表开头的零,这样你就可以” T选用该解决方案无需改动,如果该事项(例如,如果你需要的产品,而不是和)

[说明]

groupBy看起来,如果当前组的第一要素“结合在一起的”与当前元素的名单。在这种情况下,当前元素将被添加到组中,否则将启动一个新组。例如。

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

这里试验成功IST为81 'mod' 381 'mod' 9,而不是81 'mod' 25,开始一个新的组。再次,25 'mod' 5成功。

但是在我们的例子中,只要它们不是0,所有元素都“适合”在当前组中,所以我们甚至不需要看第一个元素。如果找到0,则会启动一个新组。

const (/=0)意味着只是\_ y -> y /= 0,所以无论第一个参数是什么,它只是测试的第二个元素是不为0,要知道为什么,看看定义:

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

现在我们的拉姆达可以写成

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

由于从const通话只有前两个参数“幸存”的,我们有

\x y -> (/= 0) y 

......或者......

\_ y -> y /= 0 
+0

谢谢,这是我完美的解决方案,因为我需要使用foldl(+)0.所以我有这样的:map(foldl(+)0)(groupBy ... []) – mtzero 2012-04-08 17:18:25

+0

感谢您的解释,现在我更清楚地理解它。 – mtzero 2012-04-08 20:49:44

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 - 功能它适用的功能,以列表的每个元素。 在我们的情况下,该功能是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] 
+0

谢谢快速答复。是否有其他一些初学者友好的解决方案?或者我可以用我到目前为止设法实现的代码做些什么? – mtzero 2012-04-07 17:55:18

+0

@mtzero如果这不是一个真正的问题,你应该把你的问题标记为家庭作业。 – 2012-04-07 17:58:13

1

即使你无法安装到安装split包,然后用Data.List.Split作为马特维建议,你仍然可以使用一般方法:

  1. 将怪异列表拆分为0分隔符为更传统的列表列表。
  2. 总结每个列表。

所以

yourFunction = map sum . split 

现在我们必须写split。一般来说,当我们想分开一个列表来合成新的东西时,我们需要使用折叠。

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?