1

テキスト行のリストがあり、'\' で終わるすべての行を次の行に続くものとして扱いたい、つまりマージしたい。map以下の再帰コードはそれを行いますが、 , filterand all?のような巧妙な方法があるに違いありません。

reduceLeft近いですが、変更された(そして潜在的に短い)新しいリストではなく、単一の結果しか生成しません。

また、以下のコードをよりスリムにするための提案も歓迎します。

object TestX extends App {

  // Merge lines together if the former ends with '\'.
  //
  private def mergeLines( list: List[String] ): List[String] = {

    def merge( head: String, tail: List[String] ): List[String] = {
      if (head.endsWith("\\")) {
        val head2= head.dropRight(1)
        if (tail.isEmpty) {
          head2 :: Nil   // or throw an exception on bad input
        } else {
          merge( head2 + tail.head, tail.tail )
        }
      } else {
        if (tail.isEmpty)
          head :: Nil
        else 
          head :: merge( tail.head, tail.tail )     // note: cannot tailrec this
      }
    }

    if (list.isEmpty) {
      list
    } else {
      merge( list.head, list.tail )
    }
  }

  val list = "These two \\" :: "should be joined" :: "but not this." :: Nil

  val list2 = mergeLines(list)    // any standard easy way to do this? 'list.mergeIf( _.endsWith('\\') )'

  println( list2 )
  assert( list2.size == 2 )
}
4

2 に答える 2

0

foldLeft を使用して記述できます。

List("a\\", "b", "c").foldLeft(List.empty[String])((xs, x) => xs match { 
  case Nil => x :: Nil
  case _ => if (xs.head.endsWith("\\")) (xs.head.dropRight(1) + x) :: xs.tail else x :: xs 
}).reverse

不変のデータ構造を使用するため、おそらく最も効率的な方法ではありません (小さなリストには問題ありませんが、巨大なリストには適していません)。より効率的なアプローチでは、可変リストを使用します。

于 2013-03-29T10:12:34.990 に答える
0

使用できるいくつかのトリックを次に示します。

  @annotation.tailrec
  def mergeLines(xs: List[String], out: List[String] = Nil): List[String] = xs match {
    case Nil            => out.reverse
    case x :: Nil       => mergeLines(Nil, x :: out)
    case x :: y :: rest => 
      if (x endsWith """\""") mergeLines(x.init + y :: rest, out)
      else                    mergeLines(y :: rest, x :: out)
  }
于 2013-03-29T16:25:40.470 に答える