来自升序序列的连续子列表

5

给定

xs = [1,2,3,4,6,7,9,10,11]

我旨在返回

[[1,2,3,4],[6,7],[9,10,11]]

我认为可以这样做:

groupBy (\x y -> succ x == y) xs

但是这会返回:

[[1,2],[3,4],[6,7],[9,10],[11]]

一些搜索结果显示了来自Haskell Data.List建议page的以下内容。

groupBy                 :: (a -> a -> Bool) -> [a] -> [[a]]
 groupBy rel []          =  []
 groupBy rel (x:xs)      =  (x:ys) : groupBy rel zs
   where (ys,zs) = groupByAux x xs
         groupByAux x0 (x:xs) | rel x0 x = (x:ys, zs)
           where (ys,zs) = groupByAux x xs
         groupByAux y xs = ([], xs)

他们给出的一个例子正是我正在寻找的:
groupBy (\a b -> a+1 == b) [1,2,3,4,6]
[[1,2,3,4],[6]]

所以我的问题是...是否有其他方法来解决这个问题,而不是重新定义groupBy,因为这似乎有点夸张?

编辑...

我已经决定按照以下方式实现:

pattern :: (Enum a, Eq a) => (a -> a) -> [a] -> [[a]]
pattern f = foldr g []
  where g a [] = [[a]]
        g a xs | f a == head (head xs) = (a : head xs): tail xs
               | otherwise = [a]:xs

它允许这样的事情:

*Main Map> pattern succ "thisabcdeisxyz"
["t","hi","s","abcde","i","s","xyz"]
*Main Map> pattern (+ 3) [3,6,9,12,1,2,3,2,5,8,23,24,25]
[[3,6,9,12],[1],[2],[3],[2,5,8],[23],[24],[25]]

或者完全像group一样运行--虽然没有任何理由。
*Main Map> let xs = [1,1,1,2,3,4,5,6,6,6,5]
*Main Map> group xs == pattern id xs
True
2个回答

5
有许多方法可以达到这个目的。其中一种方法可以使用foldr函数。
f = foldr g []
  where g a [] = [[a]]
        g a xs@(x:xs') | a+1 == head x = (a : x): xs'
                       | otherwise = [a]:xs

现在来实践一下

*Main> f [1,2,3,4,6,7,9,10,11]
[[1,2,3,4],[6,7],[9,10,11]]

你可以/应该在 g 函数中对 xs 进行模式匹配,即 g a xs@(x:xs'),并使用 xxs' 代替头部和尾部调用。 - huon
@dbaupp 我之前试过这种方法,但是一直延伸到第二层会让代码非常难以阅读。最好只在一层使用它。 - Satvik

3
如果xs严格递增,则
 myGrouping = map (map snd) . groupBy (\(u, v) (x, y) -> u - v == x - y) . zip [0..]

解决您的问题。
Prelude> myGrouping [1,2,3,4,6,7,9,10,11]
[[1,2,3,4],[6,7],[9,10,11]]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接