将列表拆分成多个具有固定数量元素的列表
如何将元素列表拆分成最多N个项目的列表?
例如:给出一个包含7个元素的列表,创build4个组,最后一个组可能会包含更less的元素。
split(List(1,2,3,4,5,6,"seven"),4) => List(List(1,2,3,4), List(5,6,"seven"))
我想你正在寻找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))
或者如果你想自己做:
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) }
我添加了split方法的尾recursion版本,因为有一些关于尾recursion和recursion的讨论。 我已经使用tailrec注释来强制编译器抱怨的情况下,实施不是确实尾巴recusive。 尾recursion我相信变成了引擎盖下的循环,因此即使是大型列表也不会造成问题,因为堆栈不会无限增长。
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) }
使用滑动方法可以更简单地完成任务。 它以这种方式工作:
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))
我认为这是使用splitAt而不是采取/放下的实现
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)