Splitting a list in a certain number of subscriptions

I want to split the list into a “certain number” of subscribers.

That is, for example, if I have a List(34, 11, 23, 1, 9, 83, 5) and the number of expected sublists is 3, then I want List(List(34, 11), List(23, 1), List(9, 83, 5)) .

How can I do it? I tried grouped , but it doesn't seem to do what I want.

PS: This is not a homework question. Please give a direct solution instead of some vague suggestions.

EDIT:

A slight change in requirements ...

Given the list of List(34, 11, 23, 1, 9, 83, 5) and the number of subscriptions = 3, I want the result to be List(List(34), List(11), List(23, 1, 9, 83, 5)) . (i.e. 1 item in the list, except for the last list that contains all the other items.)

+4
source share
5 answers

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) 
+4
source

This is a difficult call because you don’t know how many items to put in each list before you know the size of the list. If you know the size of the list, you can use the grouped ones: list.grouped((list.size + 2) / 3).toList . However, he will not share elements like you.

Question: does order matter? If the order of the elements does not need to be maintained, then there are better ways to achieve this.

+2
source

If you can endure the call to get the length of the list, then

 l.grouped( (l.length+2)/3 ).toList 

will create something similar to what you want (if val l = List(34, 11, 23, 1, 9, 83, 5) , then you will get List(List(34, 11, 23), List(1, 9, 83), List(5)) back, but if you want a roughly equal distribution across your lists, then you will need to create your own method for this - there is no library function that splits the list into equal parts by n .

Something like this will work if you want to keep order 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 will happen to return exactly what you want: List(List(34, 11), List(23, 1), List(9, 83, 5)) .

If you do not want to request the length of the list, then you can write a method that creates a bunch of buckets and introduces a new element dropwise each time.

+1
source

I don't know if this is the answer to your problem, but here is an attempt (what do you expect when count is out 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) } } 
0
source

Is grouped new in 2.8? A stand-alone solution for 2.7.7 might 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 } 

Parameterization to the list [T] is left as an exception to the reader.

0
source

Source: https://habr.com/ru/post/1310543/


All Articles