将列表拆分为已排序的子列表

时间:2010-11-17 23:15:34

标签: haskell functional-programming

如何将列表[1,2,4,1,5,7,3,4,2,3]划分为一个子列表列表,这些子列表将按断开序列的值进行拆分。例如,列表[1,2,4,1,5,7,3,4,2,3]应该产生一个子列表,如[[1,2,4],[1,5,7],[ 3,4],[2,3]。

有关此问题的任何想法或建议如何解决此问题?

感谢。

5 个答案:

答案 0 :(得分:9)

就像上面的Travis一样,我的第一个想法就是用自己的尾巴压缩列表: 但是,在这种情况下它看起来不太合适。不仅没有真正的分割功能完全符合您的要求,而且还存在一个问题,即您将在开头或结尾丢失一个元素。代替正确抽象的解决方案,请看一下:

splitAscending :: Ord a => [a] -> [[a]]
splitAscending = foldr f [] where
    f x [] = [[x]]
    f x (y:ys) = if x < head y
    -- It's okay to call head here because the list y is
    -- coming from the summary value of the fold, which is [[a]].
    -- While the sum value may be empty itself (above case), it will
    -- never CONTAIN an empty list.  In general be VERY CAREFUL when
    -- calling head.
        then (x:y):ys -- prepend x to the first list in the summary value
        else [x]:y:ys -- prepend the new list [x] to the summary value

快速而肮脏的解决方案,我希望它符合您的需求

- 另外,这是我在Stack Overflow上的第一篇文章:)

答案 1 :(得分:4)

这里有一个提示:每当你需要在处理列表时查看连续元素时,最好先将列表压缩到尾部:

Prelude> let f xs = zip xs $ tail xs
Prelude> f [1,2,4,1,5,7,3,4,2,3]
[(1,2),(2,4),(4,1),(1,5),(5,7),(7,3),(3,4),(4,2),(2,3)]

现在,您可以使用splitWhen $ uncurry (>)splitWhen来自Data.List.Split)的内容来适当地划分列表。

答案 2 :(得分:2)

你可以用2个函数来做,一个在第一个项低于第二个项时分割头,另一个用函数输出分割头的函数,并将递归调用的结果连接到自身列表的尾部。

splitList :: [Int] -> [[Int]]
splitList [] = []
splitList (x:xs) = ys : splitList zs
    where (ys,zs) = splitHead (x:xs)


splitHead :: [Int] -> ([Int], [Int])
splitHead [x] = ([x], [])
splitHead (x:y:xs)
    | x > y = ([x], (y:xs))
    | x <= y = (x:ys, zs)
    where (ys,zs) = splitHead (y:xs)

答案 3 :(得分:2)

嗯,这并不像我希望的那样干净,但现在就是这样。 使用包拆分http://hackage.haskell.org/package/split

:m+ Data.List.Split
Prelude Data.List.Split> let f ys = let ys' = zip ys (tail ys) in map (map fst) ((split . whenElt) (uncurry (>)) $ ys')

这里很可能会清理牙箍。

答案 4 :(得分:1)

怎么样

asc [] = [[]]
asc (x:xs) = map reverse $ reverse $ foldl ins [[x]] xs
    where ins ((y:ys):yss) z | z > y = (z:y:ys) : yss
                             | otherwise = [z] : (y:ys) : yss 

asc = map reverse.reverse.foldl ins [[]] 
      where ins [[]] z = [[z]]
            ins ((y:ys):yss) z | z > y = (z:y:ys) : yss
                               | otherwise = [z] : (y:ys) : yss