13

文字列型のリストがある場合、

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"withの位置を見つけて、indexOfそのようにリストを分割するか、または同様のアプローチを使用することを考えましtakeWhile (i => i != "BREAK")たが、もっと良い方法があるかどうか疑問に思っていますか?

それが役に立ったら、リストには3セットのアイテムしか存在しないことを私は知っていitemsます(したがって、2つの"BREAK"マーカー)。

4

6 に答える 6

11
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))

更新:上記のバージョンは簡潔で効果的ですが、2つの問題があります。エッジケース(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)
}

これは、の最初のバージョンで使用しListBufferた実装とよく似た、内部でを使用します。List.spansplitBySeparator

于 2013-01-30T21:36:50.657 に答える
6

別のオプション:

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))
于 2013-01-30T22:00:33.417 に答える
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))
于 2013-01-30T21:33:15.233 に答える
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の回答(わずかに異なる質問に対する)でのspanの使用と同じように何かを見てください。

于 2013-01-31T12:49:50.240 に答える
0

List.unfoldの使用(Scala 2.13以降):

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で実行されるコード。

于 2020-12-06T16:34:11.333 に答える
-1
val q = items.mkString(",").split("BREAK").map("(^,|,$)".r.replaceAllIn(_, "")).map(_.split(","))

ここで、「、」は、アイテムリストのどの文字列にも表示されない一意の区切り文字です。必要に応じて、別のセパレータを選択できます。

items.mkString(",")すべてを1つの文字列に結合します

.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)
于 2016-06-18T16:01:28.563 に答える