2012-06-21 26 views
5

Dado un List comoDividir una lista Scala en listas de intercalación n

List(1, 2, 3, 4, 5, 6, 7) 

¿cuál es la mejor manera de dividirlo en n sub-listas, poner los elementos en cada lista en un round-robin?

p. Ej. si n = 3, el resultado debe ser

List(List(1, 4, 7), List(2, 5), List(3, 6)) 

pensé que habría un método en el API de colecciones de hacer esto, pero me parece que no puede encontrarlo.

puntos extra por clase de una sola línea;)

+0

Una pregunta similar, usando corrientes: http: // stackoverflow .com/questions/17115345/split-a-stream-in-many – AmigoNico

Respuesta

10
scala> def round[T](l: List[T], n: Int) = (0 until n).map{ i => l.drop(i).sliding(1, n).flatten.toList }.toList 
round: [T](l: List[T], n: Int)List[List[T]] 

scala> round((1 to 7).toList, 3) 
res4: List[List[Int]] = List(List(1, 4, 7), List(2, 5), List(3, 6)) 
4

Aquí es un simple de una sola línea:

scala> List.range(1, 10) 
res11: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9) 

scala> res11.grouped(3).toList.transpose 
res12: List[List[Int]] = List(List(1, 4, 7), List(2, 5, 8), List(3, 6, 9)) 

Por desgracia, no funcionará cuando la lista no es transposeable .

scala> List.range(1, 8).grouped(3).toList.transpose 
java.lang.IllegalArgumentException: transpose requires all collections have the 
same size 

Usted puede utilizar el siguiente método para hacerlo transposeable, y luego aplicar el enfoque anterior.

scala> def extend[A](xs: List[A], c: Int): List[Option[A]] = { 
    | val n = Stream.iterate(c)(c +).find(_ >= xs.length).get 
    | xs.map(Some(_)).padTo(n, None) 
    | } 
extend: [A](xs: List[A], c: Int)List[Option[A]] 

scala> List.range(1, 8) 
res13: List[Int] = List(1, 2, 3, 4, 5, 6, 7) 

scala> extend(res13, 3).grouped(3).toList.transpose.map(_.flatten) 
res14: List[List[Int]] = List(List(1, 4, 7), List(2, 5), List(3, 6)) 

Armar:

scala> def round[A](xs: List[A], c: Int) = { 
    | val n = Stream.iterate(c)(c +).find(_ >= xs.length).get 
    | val ys = xs.map(Some(_)).padTo(n, None) 
    | ys.grouped(c).toList.transpose.map(_.flatten) 
    | } 
round: [A](xs: List[A], c: Int)List[List[A]] 

scala> round(List.range(1, 10), 3) 
res16: List[List[Int]] = List(List(1, 4, 7), List(2, 5, 8), List(3, 6, 9)) 

scala> round(List.range(1, 8), 3) 
res17: List[List[Int]] = List(List(1, 4, 7), List(2, 5), List(3, 6)) 
+0

'ys.grouped (3)' ¿es un error tipográfico? – senia

+0

@senia, ¿por qué sería un error tipográfico? – missingfaktor

+0

debe ser 'ys.grouped (c)' – senia

0

Si no se preocupan por lo que es round robin que puede hacer:

val list = List(1, 2, 3, 4, 5, 6, 7) 
list.grouped(Math.ceil(list.size/3)) 
Cuestiones relacionadas