Is the "list of groups by size" multiple?
I ran into this problem: grouping list items in a package of the same size so that
> groupBy 3 [1..10] [[1,2,3], [4,5,6], [7,8,9], [10]] Nothing is really hard to do, but at first I was surprised that I could not find a function for it. My first attempt was
groupBy _ [] = [] groupBy n xs = g : groupBy n gs where (g, gs) = splitAt n xs So far so good, it works even on an endless list. However, I do not like the first line of groupBy _ [] = [] . It seems like a good candidate for a fold, but I could not figure it out.
So can this function be recorded as a fold or as a single liner?
Update
My single liner attempt:
groupBy' nl = map (map snd) $ groupBy ((==) `on` fst) $ concatMap (replicate n) [1..] `zip` l It took me 10 times more to write my initial attempt.
Update 2
After Ganesh's answer and using unfoldr and unfoldr help pointfree I came out with this confusing point solution
groupBy' n = unfoldr $ listToMaybe . (ap (>>) (return.splitAt n)) You can do it like a fold with some gymnastics, but it is much better than unfold :
unfoldr (\xs -> if null xs then Nothing else Just (splitAt n xs)) [You need to import Data.List , if you have not done so already]
unfoldr type:
unfoldr :: (b -> Maybe (a, b)) -> b -> [a] The idea of unfoldr is that the producing function decides whether to stop ( Nothing ) or continue to move ( Just ). If the result is Just , then the first element of the tuple is the next element of the output list, and the second element is again passed to the generation function.
As @leftroundabout noted in a commentary on this question, the reversal here is much more natural, since it treats the elements of the output list as similar to each other, whereas in folding the elements of the input list should be considered in the same way. In this case, the need to start a new sublist for each element n input list makes this more difficult.