2012-04-07 69 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?