I need to split a list into equal sublists, e. g [1..9]
split into groups of 3 will be [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
. I have accomplished this task in the following way:
splitInGroupsOf n = takeWhile ((n ==) . length)
. map fst
. drop 1
. iterate (\(res, list) -> splitAt n list)
. (,) []
where iterate creates list of tuples with first n
elements and rest of list. This way I had to use (,) []
on argument to ensure correct type, and unwrap result afterwards. My questions are
- is there a better/more elegant way of performing same task?
- is there some standard function I should make use of?
P.S.: I'm not sure where to ask simple Haskell-related questions and will appreciate if someone points me a better place for this than SE.
2 Answers 2
There are Data.List.Split.chunksOf
and Data.List.Grouping.splitEvery
implementations of this routine in specialized packages (and a number included in other application packages: search by Int -> [a] -> [[a]]
signature on Hayoo).
I think splitEvery
implementation is pretty elegant:
splitEvery :: Int -> [a] -> [[a]]
splitEvery _ [] = []
splitEvery n xs = as : splitEvery n bs
where (as,bs) = splitAt n xs
-
\$\begingroup\$ strangely enough, Hoogle is unable to find these functions. I've got a second question: when I search Hayoo for
Int -> [a] -> [[a]]
thenchunksOf
is not at top, but when I searchInt -> [e] -> [[e]]
, thenchunksOf
is first. How am I supposed to guess what letter to use as a type variable? \$\endgroup\$sukhmel– sukhmel2014年04月30日 17:13:24 +00:00Commented Apr 30, 2014 at 17:13
The ready made function chunksOf
works very well. When tasked to create 3 elements in sublists with 11 elements in the source list, two elements will be in the last sublist of the result. The following function also includes trailers.
mklsts n = takeWhile (not.null) . map (take n) . iterate (drop n)
I use this as pairs
with a 2 for n
and no n
parameter. Pairs rock.
Edit/Add 4/12/2018
The match up of iterate
and splitOn
is one made in hell. In the questioner above, placing splitOn
in a lambda
may have compounded the problems. It is possible to make splitOn
work with iterate
but you have to ditch the fst
of the tuple produced. That defeats the entire purpose. It is way cleaner and easier to use drop n
with iterate
. The results are the same. That's what the preceding function does. Otherwise, it's the same idea.
Here is a novel way of producing the identical results using tails
imported from Data.List
in a list comprehension. It picks up stragglers, too.
ts n ls = [take n l|l<-init$tails ls,odd (head l)]
The parameters are size-of-sublist and list
Edit 4/17/2018
Well, since I had some time at work a list comprehension version that does not use tails
, a recursive version and a map
version.
ttx s ls=[take s.drop x$ls|x<-[0,s..s*1000]]
Recursive
tkn n []=[];tkn n xs=[take n xs]++(tkn n $ drop n xs)
Map
tp n ls=takeWhile(not.null)$ map(take n.flip drop ls) [0,n..]
The list comprehension is virtually infinite. Change [0,s..s*200]
to [0,s..]
for true infinity. The recursive is, of course, inherently infinite and the map function uses a big takeWhile (not.null)
to end itself.
-
\$\begingroup\$ "The ready made function
chunksOf
"? WhichchunksOf
do you speak of? Where do you address the code of the original poster? Did you intend to comment leventov's answer instead? \$\endgroup\$Zeta– Zeta2018年04月12日 07:03:18 +00:00Commented Apr 12, 2018 at 7:03 -
\$\begingroup\$ The questions are two.
1 is there a better/more elegant way of performing same task? 2. Is there some standard function I should make use of? It is implied, the code of the original works fine. What I suggest as an alternative is shorter and clear. More elegant? It is relative I thinks so. Am I wrong? i tried so hard to use
splitAt` but this resulted instead out of frustration. \$\endgroup\$fp_mora– fp_mora2018年04月12日 07:59:52 +00:00Commented Apr 12, 2018 at 7:59 -
1\$\begingroup\$ Sure, but on Code Review, we review code. We do not only provide an alternative solution without an explanation why its better. I can apply the same critcism on leventov's answer, by the way. \$\endgroup\$Zeta– Zeta2018年04月12日 08:14:13 +00:00Commented Apr 12, 2018 at 8:14
-
1\$\begingroup\$ Thank you so much for the clarification. Criticisms leveled at me are usually the opposite. I can be tedious. My interest in this function is not incidental nor frivolous. The value is information contained in the sublists exceed that of the source list so they can streamline code and lessen logic. There are few things I value more than criticism. Thank you so very much. \$\endgroup\$fp_mora– fp_mora2018年04月12日 16:10:19 +00:00Commented Apr 12, 2018 at 16:10