如果我有一个String类型的列表,
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)
如何根据特定的字符串/模式(n
,在这种情况下)将其拆分为"BREAK"
个单独的列表。
我已经考虑过使用"BREAK"
找到indexOf
的位置,然后按照这个方式拆分列表,或者使用与takeWhile (i => i != "BREAK")
类似的方法,但我想知道是否有更好的方法?
如果有帮助,我知道items
列表中只有3组项目(因此有2个"BREAK"
标记)。
答案 0 :(得分: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")
结果:
res1: List[List[String]] = List(List(Apple, Banana, Orange, Tomato, Grapes), List(Salt, Pepper), List(Fish, Chicken, Beef))
更新:上述版本虽然简洁有效,但有两个问题:它不能很好地处理边缘情况(如List("BREAK")
或List("BREAK", "Apple", "BREAK")
,而不是tail recursive。所以这是另一个(命令性)版本修复它:
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)
}
它内部使用ListBuffer
,就像我在List.span
的第一个版本中使用的splitBySeparator
的实现一样。
答案 1 :(得分: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))
答案 2 :(得分:0)
这个怎么样:使用scan
来确定列表中每个元素属于哪个部分。
val l = List("Apple","Banana","Orange","Tomato","Grapes","BREAK","Salt","Pepper","BREAK","Fish","Chicken","Beef")
val count = l.scanLeft(0) { (n, s) => if (s=="BREAK") n+1 else n } drop(1)
val paired = l zip count
(0 to count.last) map { sec =>
paired flatMap { case (x, c) => if (c==sec && x!="BREAK") Some(x) else None }
}
// Vector(List(Apple, Banana, Orange, Tomato, Grapes), List(Salt, Pepper), List(Fish, Chicken, Beef))
答案 3 :(得分:0)
这也不是尾递归,但它适用于边缘情况:
def splitsies[T](l:List[T], sep:T) : List[List[T]] = l match {
case head :: tail =>
if (head != sep)
splitsies(tail,sep) match {
case h :: t => (head :: h) :: t
case Nil => List(List(head))
}
else
List() :: splitsies(tail, sep)
case Nil => List()
}
唯一令人讨厌的事情:
scala> splitsies(List("BREAK","Tiger"),"BREAK")
res6: List[List[String]] = List(List(), List(Tiger))
如果你想更好地处理分隔符启动的情况,请查看与Martin answer中使用span不同的东西(稍微不同的问题)。
答案 4 :(得分:0)
val p: String => Boolean = _ != "BREAK"
val result: List[List[String]] = List.unfold(items) {
case Nil =>
None
case l if p(l.head) =>
Some(l.span(p))
case _ :: tail =>
Some(tail.span(p))
}
代码在Scastie处运行。
reverse
+ foldLeft
:def splitAtElement[T](list: List[T], element: T): List[List[T]] = {
list.reverse.foldLeft(List(List[T]()))((l, currentElement) => {
if (currentElement == element) {
List() :: l
} else {
(currentElement :: l.head) :: l.tail
}
})
}
代码在Scastie处运行。
foldRight
:def splitBySeparator[T](list: List[T], sep: T): List[List[T]] = {
list.foldRight(List(List[T]()))((s, l) => {
if (sep == s) {
List() :: l
} else {
(s :: l.head) :: l.tail
}
}).filter(_.nonEmpty)
}
代码在Scastie处运行。
答案 5 :(得分:-1)
val q = items.mkString(",").split("BREAK").map("(^,|,$)".r.replaceAllIn(_, "")).map(_.split(","))
这里","是一个唯一的分隔符,不会出现在项目列表中的任何字符串中。如果需要,我们可以选择不同的分隔符。
items.mkString(",")
将所有内容组合成一个字符串
.split("BREAK") // which we then split using "BREAK" as delimiter to get a list
.map("(^,|,$)".r.replaceAllIn(_, "")) // removes the leading/trailing commas of each element of the list in previous step
.map(_.split(",")) // splits each element using comma as seperator to give a list of lists
scala> val q = items.mkString(",").split("BREAK").map("(^,|,$)".r.replaceAllIn(_, "")).map(_.split(","))
q: Array[Array[String]] = Array(Array(Apple, Banana, Orange, Tomato, Grapes), Array(Salt, Pepper), Array(Fish, Chicken, Beef))
scala> q(0)
res21: Array[String] = Array(Apple, Banana, Orange, Tomato, Grapes)
scala> q(1)
res22: Array[String] = Array(Salt, Pepper)
scala> q(2)
res23: Array[String] = Array(Fish, Chicken, Beef)