Reputation: 1053
I want to divide a list in "a specific number of" sublists.
That is, for example if I have a list List(34, 11, 23, 1, 9, 83, 5)
and the number of sublists expected is 3 then I want List(List(34, 11), List(23, 1), List(9, 83, 5))
.
How do I go about doing this? I tried grouped
but it doesn't seem to be doing what I want.
PS: This is not a homework question. Kindly give a direct solution instead of some vague suggestions.
EDIT:
A little change in the requirements...
Given a list List(34, 11, 23, 1, 9, 83, 5)
and number of sublists = 3, I want the output to be List(List(34), List(11), List(23, 1, 9, 83, 5))
. (i.e. 1 element per list except for the last list which holds all the remaining elements.)
Upvotes: 4
Views: 4123
Reputation: 92026
In response to your changed requirements,
def splitN[A](list: List[A], n: Int): List[List[A]] =
if(n == 1) List(list) else List(list.head) :: splitN(list.tail, n - 1)
Upvotes: 4
Reputation: 36229
Is grouped
new in 2.8? A selfmade solution for 2.7.7 could look like this:
def splitTo (li: List [Int], count: Int) : List [List [Int]] = {
val size = li.length / count
if (count > 1) li.take (size) :: splitTo (li.drop (size), count-1) else
li :: Nil
}
Parametrizing to List [T] is left as an excecise to the reader.
Upvotes: 0
Reputation: 15717
Don't know it it answer to your problem, but here a try (what do you expect when count is outside of range) ?
def group[T](list:List[T], count:Int):List[List[T]] = {
if (count <= 0 || count >= list.length)
List(list)
else {
val numElm = list.length / count
def loop(list:List[T], i:Int):List[List[T]] = {
i match {
case 0 => List(list)
case 1 => List(list)
case _ => {
val l = list.splitAt(numElm)
l._1 :: loop(l._2, i-1)
}
}
}
loop(list, count)
}
}
Upvotes: 0
Reputation: 167891
If you can tolerate a call to get the length of the list, then
l.grouped( (l.length+2)/3 ).toList
will produce something akin to what you want (if val l = List(34, 11, 23, 1, 9, 83, 5)
then you'll get List(List(34, 11, 23), List(1, 9, 83), List(5))
back. But if you want approximately equal distribution across your lists, then you'll have to create your own method to do it--there isn't a library function that partitions a list equally into n
pieces.
Something like this would work, if you want to keep the pieces in order:
def chopList[T](
l: List[T], pieces: Int,
len: Int = -1, done: Int = 0, waiting: List[List[T]]=Nil
): List[List[T]] = {
if (l isEmpty) waiting.reverse
else {
val n = (if (len<0) l.length else len)
val ls = l.splitAt( (n.toLong*(done+1)/pieces - n.toLong*done/pieces).toInt )
chopList(ls._2,pieces,n,done+1,ls._1 :: waiting)
}
}
and this happens to return exactly what you want: List(List(34, 11), List(23, 1), List(9, 83, 5))
.
If you don't want to ask for the length of the list, then you can write a method that creates a bunch of buckets and drops a new item in each in turn.
Upvotes: 2
Reputation: 297165
That's a tough call, because you don't know how many elements to put into each list before you know the size of the list. If you do know the size of the list, you can use grouped: list.grouped((list.size + 2) / 3).toList
. It will not divide the elements like you did, though.
Question: does the order matter? If the order of the elements need not be preserved, then there are better ways of accomplishing this.
Upvotes: 2