它的签名必须如下所示:
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
我的函数应该将输入列表的元素分组到输出列表中,这些元素基于元素是否相等或者是否存在严格单调的递增部分列表。
终止的例子:
-- groupBy (==) groups the equal elements
groupBy (==) [0, 0, 1, 1, 2, 2] == [[0, 0], [1, 1], [2, 2]]
groupBy (==) [0, 1, 2] == [[0], [1], [2]]
-- groupBy (<) returns the strictly monotonous incrementing partlists
groupBy (<) [0, 1, 2, 1, 2, 3] == [[0,1,2],[1,2,3]]
groupBy (<) [3, 4, 5] == [[3, 4, 5]]
groupBy (>=) [3, 3, 1, 5] == [[3,3,1],[5]] --- monotonous decrementing
-- partlists, where the consecutive elements' difference is 1:
groupBy (\x y -> abs (x - y) == 1) [0, 1, 3, 4] == [[0, 1], [3, 4]]
groupBy (\x y -> abs (x - y) == 1) [1, 2, 3, 2, 1, 10, 11] == [[1,2,3,2,1],[10,11]]
提前感谢您的帮助:)
答案 0 :(得分:0)
看看这里必须进行的比较。您提供了一个函数f :: a -> a -> Bool
,只要它保持为真,就会对每个项目进行分组,换句话说:
groupBy (>=) [3, 3, 1, 5, 4]
[3]
3 >= 3 = True [3, 3] -- add RHS value
3 >= 1 = True [3, 3, 1]
1 >= 5 = False -- new group!
[5]
5 >= 4 = True [5, 4]
这看起来像是递归给我。你的内部函数应该保留一个累加器,查看列表中的每个元素并决定A)将它包含在当前累加器中或B)给累加器返回并根据f
的结果开始一个新的累加器。
将groupBy
定义为执行实际工作的辅助函数的包装器可能会有所帮助。
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy f (x:xs) = go f [x] xs
where
-- base case: no values left to check
go _ acc [] = [acc]
-- recursive case
go f acc@(y:_) (x:xs)
| y `f` x = go f (x:acc) xs -- add to current group
| otherwise = acc : go f [x] xs -- start a new group
请注意,上面有一个微妙的错误,我留下来用于说明目的(也因为我先用这种方式编写它,所以你也可以!)