给定haskell中的排序列表,如何获得分段列表,其中连续的数字放在同一列表中。例如,如果我有一个排序列表[1,2,3,4,7,8,10,12,13,15]
,结果将为[[1,2,3,4],[7,8],[10],[12,13],[15]]
答案 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.Function
和Data.List
。)