在 Scala 中按给定事件对列表进行分组

Group list by given occurrence in Scala

我有一个字符串列表,我试图将其按顺序拆分为单独的列表,对第 4 次出现的情况进行分组,即此列表:

val data = List("1", "2", "3", "4", "5", "6", "7", "8") 

应分组为

val list1 = List("1", "5")
val list2 = List("2", "6")
val list3 = List("3", "7")
val list4 = List("4", "8")

我不确定我是否试图将其过于复杂化,但我能想到的唯一方法是首先使用 sliding 对元素进行分组,例如:

data.sliding(4,4).toList 

结果

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

然后实现我自己的 unzip 方法,该方法将上述内容分组为我想要的输出。

有人可以告诉我是否有更简单的方法吗?

你可以用.transpose对列表.sliding生成:

scala> val data = List("1", "2", "3", "4", "5", "6", "7", "8") 
data: List[String] = List(1, 2, 3, 4, 5, 6, 7, 8)

scala> data.sliding(4, 4).toList
res1: List[List[String]] = List(List(1, 2, 3, 4), List(5, 6, 7, 8))

scala> data.sliding(4, 4).toList.transpose
res2: List[List[String]] = List(List(1, 5), List(2, 6), List(3, 7), List(4, 8))

zipsliding

之后
scala> val data = List("1", "2", "3", "4", "5", "6", "7", "8")
data: List[String] = List("1", "2", "3", "4", "5", "6", "7", "8")

scala> val result = data.sliding(4, 4).toList
result: List[List[String]] = List(List("1", "2", "3", "4"), List("5", "6", "7", "8"))

scala> result.transpose
res7: List[(String, String)] = List(("1", "5"), ("2", "6"), ("3", "7"), ("4", "8"))

如果元组作为输出,那就相当整洁了:

 val tuples = data zip data.drop(4)
 //> tuples  : List[(String, String)] = List((1,5), (2,6), (3,7), (4,8))

把它们变成List:

tuples.map{case(a,b) => List(a, b)} 
//> List[List[String]] = List(List(1, 5), List(2, 6), List(3, 7), List(4, 8))

编辑:显示关于仅使用 8 的评论不正确

 def pairs[A](xs:List[A], n:Int) =
 (xs zip xs.drop(n)).map{case(a,b) => List(a, b)}

pairs(List("1","2", "3", "4", "5", "6", "7", "8"), 4)
// List(List(1, 5), List(2, 6), List(3, 7), List(4, 8))
pairs(List("1","2", "3", "4", "5", "6", "7", "8", "9"), 4)
// List(List(1, 5), List(2, 6), List(3, 7), List(4, 8), List(5, 9))

pairs(List("1","2", "3", "4", "5", "6", "7", "8", "9", "10"), 4)
// List(List(1, 5), List(2, 6), List(3, 7), List(4, 8), List(5, 9), List(6, 10))
pairs(List("1","2", "3", "4"), 4)
// List()
pairs(List("1","2", "3"), 4)
// List()

适用于每个列表长度的版本:

def groupNth[A](n: Int, list: List[A]): List[List[A]] = {
  val (firstN, rest) = list.splitAt(n)
  val groupedRest = if (rest.nonEmpty) groupNth(n, rest) else Nil
  // null.asInstanceOf[A] is of course cheating, but the value is never used
  firstN.zipAll(groupedRest, null.asInstanceOf[A], Nil).map {
    case (h, t) => h :: t
  }
}


println(groupNth(4, Nil))
// List()
println(groupNth(4, List(1, 2, 3)))
// List(List(1), List(2), List(3))
println(groupNth(4, List(1, 2, 3, 4, 5, 6, 7, 8)))
// List(List(1, 5), List(2, 6), List(3, 7), List(4, 8))
println(groupNth(4, List(1, 2, 3, 4, 5, 6, 7, 8, 9)))
// List(List(1, 5, 9), List(2, 6), List(3, 7), List(4, 8))
println(groupNth(4, List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)))
// List(List(1, 5, 9), List(2, 6, 10), List(3, 7, 11), List(4, 8, 12))