2016-03-14 21 views
1

說我想在列表的末尾刪除所有零:如何模式匹配列表的結尾?

removeEndingZeros :: (Num a, Eq a) => [a] -> [a] 
removeEndingZeros (xs ++ [0]) = removeEndingZeros xs 
removeEndingZeros xs   = xs 

這不,因爲在參數中(++)運營商的合作。我如何通過模式匹配來確定列表的結尾?

+2

[可以使用模式匹配來綁定列表的最後一個元素嗎?](http://stackoverflow.com/questions/7576843/can-you-use-pattern-matching-to-bind-the最後一個元素的列表) –

+0

如何解決問題,你可以刪除前導零?如果你不限於使用列表,那麼Data.Sequence可能是有用的 – epsilonhalbe

回答

7

有在Data.List一個函數來做到這一點:

dropWhileEnd :: (a -> Bool) -> [a] -> [a] 
dropWhileEnd p = foldr (\x xs -> if p x && null xs then [] else x : xs) [] 

所以,你可以用

dropWhileEnd (== 0) 

下降的尾隨零

另一個非常相似,功能可以實現這樣的:

dropWhileEnd2 :: (a -> Bool) -> [a] -> [a] 
dropWhileEnd2 p = foldr (\x xs -> if null xs && p x then [] else x : xs) [] 

dropWhileEnd2 p具有完全相同的語義reverse . dropWhile p . reverse,但可以合理地預期常數因子要快。 dropWhileEnd與其他人有不同的,不可比較的嚴格性(在某些方面它更嚴格,其他方面更嚴格)。

你能弄清楚在什麼情況下每一種情況都可以預計會更快?

6

在標準的Haskell中,你不能在列表的末尾模式匹配。由於定義了列表的方式,因此訪問列表的末尾需要時間與列表的長度成線性關係。既然你不能沒有在最壞的情況下兩次遍歷下降尾隨零,明顯的解決方案是好的 - 從列表中的反向下降前導零,然後再反向恢復原來的秩序:

removeEndingZeros = reverse . dropWhile (== 0) . reverse 
+0

我想這是定義列表方式的結果。儘管如此,謝謝你的確切答案。 –

+1

@MarkAnastos實際上你可以用一些聰明的方法一次性完成這個任務。見dfeuer的答案。 – Carl

+0

Carl - 「dropWhileEnd」如何不需要兩次傳球?它看起來像'foldr'遍歷列表直到結束,從這一點重建列表。除非我錯過了一些東西,它只會節省一次遍歷。無論如何,這顯然是一個比我的更好的解決方案:) –

相關問題