如果我有一个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"标记).
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.
另外一个选项:
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)