如何将元素列表拆分为最多N个项目的列表?
例如:给定一个包含7个元素的列表,创建4个组,使最后一个组可能包含更少的元素。
split(List(1,2,3,4,5,6,"seven"),4)
=> List(List(1,2,3,4), List(5,6,"seven"))
答案 0 :(得分:183)
我认为你正在寻找grouped
。它返回一个迭代器,但您可以将结果转换为列表,
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))
答案 1 :(得分:8)
或者如果你想自己制作:
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)
}
使用:
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))
编辑:经过2年后的审核,我不推荐这个实现,因为size
是O(n),因此这个方法是O(n ^ 2),这可以解释为什么内置方法对于大型列表变得更快,如下面的评论中所述。您可以按如下方式有效实施:
def split[A](xs: List[A], n: Int): List[List[A]] =
if (xs.isEmpty) Nil
else (xs take n) :: split(xs drop n, n)
甚至(略微)使用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)
}
答案 2 :(得分:8)
使用滑动方法执行任务的方法更简单。 它的工作原理如下:
val numbers = List(1, 2, 3, 4, 5, 6 ,7)
假设您想将列表分成较小的3号列表。
numbers.sliding(3, 3).toList
会给你
List(List(1, 2, 3), List(4, 5, 6), List(7))
答案 3 :(得分:3)
我正在添加一个tail递归版本的split方法,因为有一些关于尾递归和递归的讨论。我已经使用了tailrec注释来强制编译器抱怨,以防实现不是尾部重用。尾递归我相信会变成一个循环,因此即使对于大型列表也不会导致问题,因为堆栈不会无限增长。
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)
}
答案 4 :(得分:0)
我认为这是使用splitAt而不是take / drop
的实现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)