這裏的另一種方法。目前,假設列表中沒有像您的示例那樣的相鄰元素。如果列表lst
與其自身的尾巴相比,元件逐元素:
> let lst = [1,2,31,23,22,1,43]
> let dir = zipWith compare lst (tail lst)
> dir
[LT,LT,GT,GT,GT,LT]
然後dir
代表相鄰元件是否增加或減少。如果我們重複這個列表的頭:
> let dir' = head dir : dir
> dir'
[LT,LT,LT,GT,GT,GT,LT]
然後dir'
對應如何名單[1,2,31,23,22,1,43]
應進行分組。通過與lst
荏苒dir'
並通過dir'
元素分組,我們得到:
> import Data.Function -- for `on`
> let groups = groupBy ((==) `on` fst) (zip dir' lst)
> groups
[[(LT,1),(LT,2),(LT,31)],[(GT,23),(GT,22),(GT,1)],[(LT,43)]]
,我們可以過濾:
因此,把所有這些組合起來,我們得到了一個更高階的解決方案:
groupIncDec' :: Ord a => [a] -> [[a]]
groupIncDec' lst =
let dir = zipWith compare lst (tail lst)
in map (map snd)
$ groupBy ((==) `on` fst)
$ zip (head dir : dir) lst
這並不與相鄰的重複元素列表正常工作,但我們可以採取這樣的名單:
lst' = [1,2,31,31,23,22,22,1,43]
和組它:
group lst' = [[1],[2],[31,31],[23],[22,22],[1],[43]]
,然後選擇「取消組合」它再次得到最終結果之前有效地應用上述算法。這看起來是這樣的:
groupIncDec :: Ord a => [a] -> [[a]]
groupIncDec xs =
let ys = group xs
dir = zipWith (comparing head) ys (tail ys)
in map (concatMap snd)
$ groupBy ((==) `on` fst)
$ zip (head dir : dir) ys
其工作原理是這樣:
> groupIncDec [1,2,31,23,22,1,43]
[[1,2,31],[23,22,1],[43]]
> groupIncDec [1,2,31,31,23,22,22,1,43]
[[1,2,31,31],[23,22,22,1],[43]]
這是什麼功能做什麼呢?我無法單單從這個例子中看出來。 – AJFarmar
好像''groupIncDec''可以包裝一對共同遞歸'([[a]],[a]) - >([[a]],[a])'函數,當'x'爲朝着相同的方向,當'x'朝相反的方向時互相調用,並且當'xs'是'[]'時基本出來。 –
你不能使用'groupBy',因爲它沒有內存,它一次只能看兩個相鄰的元素。 –