简体   繁体   中英

Transform a list into a list of lists with fold in haskell

I have this code:

fromList :: Int -> [Int] -> [[Int]]
fromList y = takeWhile (not.null) . map (take y) . iterate (drop y) 

An example of what this does: -> fromList 4 [1..19]

[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16],[17,18,19]]

How can I make this code using a fold?

Here's a pretty elegant solution using foldr :

fromList :: Int -> [a] -> [[a]]
fromList n = foldr (\v a ->
    case a of
        (x:xs) -> if length x < n then (v:x):xs else [v]:a
        _ -> [[v]]
    ) []

Essentially, the accumulator is the end value, and for each value in the list it checks if there's still space to put it in an existing chunk, and if there isn't then it puts it in a new chunk. Sadly, due to using foldr , extra elements are put on the left side instead of the right side. This can be fixed by using a slightly slower (and maybe slightly uglier) approach with foldl (or foldl' ):

fromList :: Int -> [a] -> [[a]]
fromList _ [] = []
fromList n (x:xs) = reverse $ foldl (\a@(y:ys) v ->
    if length y < n
        then (y ++ [v]):ys
        else [v]:a
    ) [[x]] xs

Here's one way.

foo :: Int -> [t] -> [[t]]
foo k xs | k > 0  =  foldr cons [] .
          zip xs . cycle $ (False <$ [2..k]) ++ [True]
  where
  cons (a,True)   ys  =  [a] : ys
  cons (a,False)  ys  =  (a:x) : zs
                         where
                         (x,zs) | null ys   = ([], [])
                                | otherwise = (head ys, tail ys)

-- > foo 3 [1..10]
-- => [[1,2,3],[4,5,6],[7,8,9],[10]]

-- > take 4 . foo 3 $ [1..]
-- => [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]

-- > take 3 . map (take 2) . foo 3 $ [1..8] ++ undefined
-- => [[1,2],[4,5],[7,8]]

It creates the output as you have described it, and does so in a lazy enough way so that it works with infinite lists as well.

( edit: made it even lazier so that the last example would work, based off the idea by Daniel Fischer )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM