2014-04-30 34 views
2

我試圖將列表的一部分列出,而元素與以前只有一列不同。一個簡單的任務可以實現,如:Haskell按升序排列(+1)列表的一部分

takeAsc:: (Eq a, Enum a) => [a] -> [a] 
takeAsc [] = [] 
takeAsc [x] = [x] 
takeAsc (x:y:xs) 
    |y == succ x = x: takeAsc(y:xs) 
    |otherwise = [x] 

但這只是傷害了我的感情。我相信,這是相當廣泛的使用模式,我只是缺少一些特定的功能。我嘗試過使用groupBy或takeWhile,但看起來他們沒有做我想做的事。 任何人都可以指出更優雅的解決方案嗎?

+1

我覺得這個定義非常好,很正常,只是你錯過了單元素列表的情況。 –

+0

謝謝,修復。 – Triostrong

回答

3

您可以實現它作爲

takeAsc [] = [] 
takeAsc [email protected](x:xs) = (x:) $ map fst $ takeWhile (uncurry (==)) $ zip xs $ map succ xss 

您還必須包括這兩種情況下,雖然。

> takeAsc [1, 2, 3, 4] 
[1, 2, 3, 4] 
> takeAsc [1, 3, 4, 5] 
[1] 

如果你不喜歡它總是返回至少1元的非空列表,你會像你有上面使用更詳細的解決方案,但如果你去一個單線這是我能想到的最好的。

+0

謝謝,我也想過關於單行程的翻譯,但是對於最終的實現來說還不夠聰明。 – Triostrong

+0

不要說「不夠聰明」,這些模式需要一段時間才能弄清楚。您看到的解決方案越多,您就可以使用它們越多。當我開始學習haskell時,我處於相同的位置,但幾年後,這些模式變得像第二天性,就像我開始學習Python時一樣,花了一些時間來學習模式。 – bheklilr

2

一個簡單的方法來做到這將是

takeAsc :: (Enum a, Eq a) => [a] -> [a] 
takeAsc []  = [] 
takeAsc (x:xs) = (x:) . map fst . takeWhile pred . zip xs $ x:xs 
    where pred (a, b) = a == succ b 

或英文,

  1. 上的空單,空單
  2. 配對中上一個元素列表中的每個元素列表中,刪除第一個元素
  3. 取對,而succba

它避免了有些噁心明確遞歸刪除對

  • 棒的第一個元素後面的第二個元素和GHC應該足夠聰明來優化這個相當不錯。

  • +0

    儘管如此,它會刪除最後一個元素:'takeAsc [1,2,3,4] == [1,2,3]'。我想出了一個類似的實現'map fst $ takeWhile(uncurry(==))$ zip xs $ map pred $ tail xs'它可以做同樣的事情... – bheklilr

    +0

    @bheklilr固定了一些模式匹配 – jozefg

    +1

    我也會建議重命名你的本地'pred'函數,因爲它覆蓋了爲'Enum'定義的'pred'函數,這很容易導致混淆。此時我們也有基本相同的解決方案。 – bheklilr