Comment diviser une liste d'éléments en listes comportant au plus N éléments?
ex: Avec une liste de 7 éléments, créez des groupes de 4 en laissant éventuellement le dernier groupe avec moins d'éléments.
split(List(1,2,3,4,5,6,"seven"),4)
=> List(List(1,2,3,4), List(5,6,"seven"))
Je pense que vous cherchez grouped
. Il retourne un itérateur, mais vous pouvez convertir le résultat en liste,
scala> List(1,2,3,4,5,6,"seven").grouped(4).toList
res0: List[List[Any]] = List(List(1, 2, 3, 4), List(5, 6, seven))
Il existe un moyen beaucoup plus facile de faire la tâche en utilisant la méthode par glissement. Cela fonctionne de cette façon:
val numbers = List(1, 2, 3, 4, 5, 6 ,7)
Disons que vous voulez diviser la liste en petites listes de taille 3.
numbers.sliding(3, 3).toList
te donnera
List(List(1, 2, 3), List(4, 5, 6), List(7))
Ou si vous voulez créer le vôtre:
def split[A](xs: List[A], n: Int): List[List[A]] = {
if (xs.size <= n) xs :: Nil
else (xs take n) :: split(xs drop n, n)
}
Utilisation:
scala> split(List(1,2,3,4,5,6,"seven"), 4)
res15: List[List[Any]] = List(List(1, 2, 3, 4), List(5, 6, seven))
edit: après avoir examiné cela 2 ans plus tard, je ne recommanderais pas cette implémentation car size
est O (n), et par conséquent cette méthode est O (n ^ 2), ce qui expliquez pourquoi la méthode intégrée devient plus rapide pour les grandes listes, comme indiqué dans les commentaires ci-dessous. Vous pouvez implémenter efficacement comme suit:
def split[A](xs: List[A], n: Int): List[List[A]] =
if (xs.isEmpty) Nil
else (xs take n) :: split(xs drop n, n)
ou même (légèrement) plus efficacement avec splitAt
:
def split[A](xs: List[A], n: Int): List[List[A]] =
if (xs.isEmpty) Nil
else {
val (ys, zs) = xs.splitAt(n)
ys :: split(zs, n)
}
J'ajoute une version récursive de la méthode split dans la mesure où il a été question de récursion de queue et de récursivité. J'ai utilisé l'annotation tailrec pour forcer le compilateur à se plaindre au cas où l'implémentation ne serait pas réellement récusative. Je crois que la récursion de la queue se transforme en une boucle sous le capot et ne causera donc pas de problèmes, même pour une longue liste, car la pile ne grandira pas indéfiniment.
import scala.annotation.tailrec
object ListSplitter {
def split[A](xs: List[A], n: Int): List[List[A]] = {
@tailrec
def splitInner[A](res: List[List[A]], lst: List[A], n: Int) : List[List[A]] = {
if(lst.isEmpty) res
else {
val headList: List[A] = lst.take(n)
val tailList : List[A]= lst.drop(n)
splitInner(headList :: res, tailList, n)
}
}
splitInner(Nil, xs, n).reverse
}
}
object ListSplitterTest extends App {
val res = ListSplitter.split(List(1,2,3,4,5,6,7), 2)
println(res)
}
Je pense que ceci est l'implémentation utilisant splitAt au lieu de prendre/déposer
def split [X] (n:Int, xs:List[X]) : List[List[X]] =
if (xs.size <= n) xs :: Nil
else (xs.splitAt(n)._1) :: split(n,xs.splitAt(n)._2)