给定列表{% tabs %}
{% tab id = "tab-1" title = "Tab One" %}
Content in Tab 1
{% \tab %}
{% tab id = "tab-2" title = "Tab Two" %}
Content in Tab 2
{% \tab %}
{% \tabs %}
想要使用更高阶函数对元素[1,2,31,23,22,1,43]
进行分组。增加/减少列表,其中元素最初是元素按递增顺序然后按降序排列。
[[1,2,31], [23,22,1], [43]]
输出列表groupIncDec :: Ord a => [a] -> [[a]]
中的每个元素应该全部增加或全部减少,如上例所示,第一个元素[[a]]
全部增加,第二个[1,2,31]
全部减少,因为剩下一个元素,前一个状态都在减少,[23,22,1]
可以归类为全部增加。
无法弄清楚是否/如何使用[43]
。任何提示将不胜感激。
感谢。
[编辑:添加了更多描述,希望能进一步澄清这个问题。]
答案 0 :(得分:4)
这是另一种方法。暂时,让我们假设列表没有相邻的相等元素,就像你的例子一样。如果将列表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]
的分组方式。通过使用dir'
压缩lst
并按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)]]
我们可以过滤到:
> map (map snd) groups
[[1,2,31],[23,22,1],[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]]
然后在" ungrouping"之前有效地应用上述算法它再次获得最终结果。看起来像这样:
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]]
答案 1 :(得分:2)
groupBy
意味着按相等分组,而不是一般的二元关系。例如:
Prelude Data.List> groupBy (<) [1,3,2]
[[1,3,2]]
它是第一个元素1
的范围(1<3
,1<2
)。
我提出了foldl
的解决方案,但这不是一个非常干净的解决方案。
groupIncDec :: Ord a => [a] -> [[a]]
groupIncDec = map reverse . reverse . foldl f []
where f [] x = [[x]]
f ([y]:ys) x = [x,y]:ys
f (ys@(y1:y2:_):yss) x = if x < y1 && y1 < y2 || x > y1 && y1 > y2
then (x:ys):yss
else [x]:ys:yss
f
属于[[a]] -> a -> [[a]]
类型,即累积部分。
因为Haskell List擅长处理head元素(在:
的帮助下),所以结果存储在后面。因此需要map reverse . reverse
。