将列表分成子列表:相同的值被添加到一个子列表,不同的值被添加到另一个

Divide the list into sub-lists: the same values are added to one sublist and different values are added to another

将列表划分为子列表:将相同的值添加到一个子列表,将不同的值添加到另一个子列表。它需要通过列表的一次传递使用 foldr 来完成,而不是使用 ++.

例如:

ghci> splitList [1,2,2,4,5,7,7,8,9] 

[[1],[2,2],[4,5],[7,7],[8,9]]

我做了类似的事情:

splitList :: [Int] -> [[Int]]
splitList = getRes . foldr func5 ([],False,0) where
  func5 c ([],_,_) = ([[c]],False,c)
  func5 c (y@(x:xs), b, l) | c == l = ((c:x):xs, False, c)
                           | b = ((c:x):xs, False, c)
                           | otherwise = ([c]:y, True, c)

getRes :: ([[Int]], Bool, Int) -> [[Int]]
getRes (a,_,_) = a

但它并没有像我预期的那样工作...

ghci> splitList [1,2,2,4,5,7,7,8,9]

[[1],[2,2],[4,5],[7,7,8],[9]]

由于您正在使用 foldr

> splitList [1,2,2,4,5,7,7,8,9]

[[1],[2,2],[4,5],[7,7],[8,9]]

应该像

一样从右边开始工作
> splitList [1,2,2,4,5,7,7,8,9]
                              []
                           [[9]]
                         [[8,9]]
                       [[7,8,9]]
                     [[7,7],[8,9]]
                   [[5],[7,7],[8,9]]
                 [[4,5],[7,7],[8,9]]
               [[2,4,5],[7,7],[8,9]]
             [[2,2],[4,5],[7,7],[8,9]]
           [[1],[2,2],[4,5],[7,7],[8,9]]

现在剩下的就是用代码写下来了。

从上面可以看出,我们只需要将当前元素与“累加器”的头部进行比较(特殊情况除外,列表的最后两个元素是无条件收集的),同时保持“相同性”旗帜。所以可以编码为

splitList :: Eq a => [a] -> [[a]]
splitList xs = snd $ foldr g (undefined,[]) xs
  where
  g x (b,[]) = (b,[[x]])
  g x (_,[y]:t) = (x==y,[x,y]:t)
  g x (b,(a:r):t)
     | (x==a)==b  = (b,(x:a:r):t)
     | otherwise  = (not b, if b then [x]:(a:r):t
                                 else [x,a]:r:t)

测试:

> splitList [1,2,2,4,5,7,7,8,9]
[[1],[2,2],[4,5],[7,7],[8,9]]

> splitList [1,2,2,4,5,7,7,8,9,9]
[[1],[2,2],[4,5],[7,7],[8],[9,9]]

> splitList [1,2,2,4,5,7,8,9,9,9]
[[1],[2,2],[4,5,7,8],[9,9,9]]