1

我有一个文本行列表,并希望将任何以 '\' 结尾的行视为继续到下一行,即合并它们。下面的递归代码做到了,但一定有一些巧妙的方法,类似于map,filter和所有?

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

以下是您可以使用的一些技巧:

  @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 回答
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 回答