分割Haskell列表

时间:2014-12-10 16:26:24

标签: list haskell

给定haskell中的排序列表,如何获得分段列表,其中连续的数字放在同一列表中。例如,如果我有一个排序列表[1,2,3,4,7,8,10,12,13,15],结果将为[[1,2,3,4],[7,8],[10],[12,13],[15]]

3 个答案:

答案 0 :(得分:6)

这只是一个折叠者:

q :: (Enum a, Eq a) => [a] -> [[a]]
q = foldr foo []
  where
    foo x (ys@(y:_) : zzs) | succ x == y = (x:ys) : zzs
    foo x t = [x] : t
  

*主> q [1,2,3,4,7,8,10,12,13,15]

     

[[1,2,3,4],[7,8],[10],[12,13],[15]]

更新:它也可以变成折叠,在这里我使用"差异列表"让它成为现实:

type N a = Maybe ( [[a]] -> [[a]], [a] -> [a], a )

p :: (Enum a, Eq a) => [a] -> [[a]]
p = close . foldl bar Nothing
  where
    close :: N a -> [[a]]
    close Nothing = []
    close (Just (f, g, _)) = (f  . (g []:)) []

    bar :: (Enum a, Eq a) => N a -> a -> N a
    bar Nothing x = Just (id, (x:), x)
    bar (Just (f, g, y)) x | succ y == x = Just (f, g . (x:), x)
                           | otherwise = Just ( f . (g []:), (x:), x)

更新2:' f'是一个在无限列表上安全的变体:

f :: (Enum a, Eq a) => [a] -> [[a]]
f [] = []
f (x:xs) = go x xs
  where
    go x xs = let (run, rest) = getRun x xs
              in run : f rest
    getRun x t@(y:ys) | succ x == y = let (run, rest) = getRun y ys
                                      in (x:run, rest)
    getRun x t = (x:[], t)

或更短的' f' :

f :: (Enum a, Eq a) => [a] -> [[a]]
f [] = []
f (x:xs) = getRun x xs
  where
    getRun x t@(y:ys) | succ x == y = let (run : rest) = getRun y ys
                                      in (x:run) : rest
    getRun x t = (x:[]) : f t

t3 = [1,2,3,10,11,12] ++ [15..]
  

*主>取3(地图(拍5)(f t3))

     

[[1,2,3],[10,11,12],[15,16,17,18,19]]

答案 1 :(得分:1)

解决方案概要:

1-将每个元素与下一个元素配对:

(1,2) (2,3) (3,4) (4,7) (7,8) (8,10) (10,12) (12,13) (13,15) ...

2-检查每对是否连续:

(1,2) (2,3) (3,4) (4,7) (7,8) (8,10) (10,12) (12,13) (13,15) ...
True  True  True  False True  False  False   True    False   ...

3-以False值分隔列表:

(1,2) (2,3) (3,4) (4,7) | (7,8) (8,10) | (10,12) | (12,13) (13,15) | ...
True  True  True  False | True  False  | False   | True    False   | ...

4-对于每个细分,请选择fst对:

1 2 3 4 | 7 8 | 10 | 12 13

答案 2 :(得分:0)

此功能可以提供帮助

addFirstInRun::Int->[Int]->[(Int, Int)]
addFirstInRun _ [] = []
addFirstInRun lowVal (x:y:rest) | y - x > 1 = (lowVal, x):firstInRun y (y:rest)
addFirstInRun lowVal (x:rest) = (lowVal, x):firstInRun lowVal rest

它将列表中的每个值与另一个数字配对," head"目前的垃圾箱。

> addFirstInRun 1 [1,2,3,5,6,7,10]

  [(1,1),(1,2),(1,3),(5,5),(5,6),(5,7),(10,10)]

(对不起,你需要手工放入第一个....你可以写一个方便的包装来解决这个问题。)

使用此功能,您可以使用groupBy

groupBy ((==) `on` fst)

您可以使用此

清理最终答案
map (map snd)

把这一切放在一起

> map (map snd) $ groupBy ((==) `on` fst) $ addFirstInRun 1 [1,2,3,5,6,7,10]

  [[1,2,3],[5,6,7],[10]]

(您需要导入Data.FunctionData.List。)