什么是Scala通过分隔符拆分List的惯用方法?

jbn*_*unn 10 java scala

如果我有一个String类型的List,

scala> val items = List("Apple","Banana","Orange","Tomato","Grapes","BREAK","Salt","Pepper","BREAK","Fish","Chicken","Beef")
items: List[java.lang.String] = List(Apple, Banana, Orange, Tomato, Grapes, BREAK, Salt, Pepper, BREAK, Fish, Chicken, Beef)
Run Code Online (Sandbox Code Playgroud)

如何n根据某个字符串/模式("BREAK"在本例中)将其拆分为单独的列表.

我已经想过要找的位置"BREAK"indexOf,或分割的列表方式,或者采用类似的方法有takeWhile (i => i != "BREAK"),但我不知道是否有更好的方法?

如果它有帮助,我知道items列表中只有3组项目(因此有2个"BREAK"标记).

Rég*_*les 8

def splitBySeparator[T]( l: List[T], sep: T ): List[List[T]] = {
  l.span( _ != sep ) match {
    case (hd, _ :: tl) => hd :: splitBySeparator( tl, sep )
    case (hd, _) => List(hd)
  }
}

val items = List("Apple","Banana","Orange","Tomato","Grapes","BREAK","Salt","Pepper","BREAK","Fish","Chicken","Beef")
splitBySeparator(items, "BREAK")
Run Code Online (Sandbox Code Playgroud)

结果:

res1: List[List[String]] = List(List(Apple, Banana, Orange, Tomato, Grapes), List(Salt, Pepper), List(Fish, Chicken, Beef))
Run Code Online (Sandbox Code Playgroud)

更新:上面的版本,虽然简洁有效,但有两个问题:它不能很好地处理边缘情况(像List("BREAK")List("BREAK", "Apple", "BREAK"),并且,不是尾递归.所以这是另一个(命令性)版本修复此问题:

import collection.mutable.ListBuffer
def splitBySeparator[T]( l: Seq[T], sep: T ): Seq[Seq[T]] = {
  val b = ListBuffer(ListBuffer[T]())
  l foreach { e =>
    if ( e == sep ) {
      if  ( !b.last.isEmpty ) b += ListBuffer[T]()
    }
    else b.last += e
  }
  b.map(_.toSeq)
}
Run Code Online (Sandbox Code Playgroud)

它内部使用a ListBuffer,就像List.span我在第一个版本中使用的实现一样splitBySeparator.


Rya*_*pte 5

另外一个选项:

val l = Seq(1, 2, 3, 4, 5, 9, 1, 2, 3, 4, 5, 9, 1, 2, 3, 4, 5, 9, 1, 2, 3, 4, 5)

l.foldLeft(Seq(Seq.empty[Int])) {
  (acc, i) =>
    if (i == 9) acc :+ Seq.empty
    else acc.init :+ (acc.last :+ i)
}

// produces:
List(List(1, 2, 3, 4, 5), List(1, 2, 3, 4, 5), List(1, 2, 3, 4, 5), List(1, 2, 3, 4, 5))
Run Code Online (Sandbox Code Playgroud)