将列表拆分为具有固定数量元素的多个列表

Joh*_*son 111 split scala list

如何将元素列表拆分为最多N个项目的列表?

例如:给定一个包含7个元素的列表,创建4个组,使最后一个组可能包含更少的元素.

split(List(1,2,3,4,5,6,"seven"),4)

=> List(List(1,2,3,4), List(5,6,"seven"))
Run Code Online (Sandbox Code Playgroud)

Kip*_*ros 195

我想你在找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))
Run Code Online (Sandbox Code Playgroud)

  • Scala列表可以满足一切需求. (21认同)
  • @Rakshith 这听起来像是一个单独的问题。Scala 有一个神秘的侏儒来选择数据结构,它为你选择了一个流。如果你想要一个列表,你应该请求一个列表,但你也可以相信侏儒的判断。 (3认同)

小智 9

使用滑动方法可以更轻松地完成任务.它以这种方式工作:

val numbers = List(1, 2, 3, 4, 5, 6 ,7)
Run Code Online (Sandbox Code Playgroud)

假设您想将列表分成大小为3的较小列表.

numbers.sliding(3, 3).toList
Run Code Online (Sandbox Code Playgroud)

会给你

List(List(1, 2, 3), List(4, 5, 6), List(7))
Run Code Online (Sandbox Code Playgroud)


Lui*_*hys 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)
}
Run Code Online (Sandbox Code Playgroud)

使用:

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))
Run Code Online (Sandbox Code Playgroud)

编辑: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)
Run Code Online (Sandbox Code Playgroud)

甚至(稍微)更有效地使用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)
  }
Run Code Online (Sandbox Code Playgroud)

  • `xs splitAt n`是组合`xs take n`和`xs drop n`的替代方案 (4认同)

Mik*_*ike 5

我添加了 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)
}
Run Code Online (Sandbox Code Playgroud)