如何在Scala中合并选定的列表条目? (即产生一个可能更短的清单)

时间:2013-03-29 10:04:19

标签: scala

我有一个文本行列表,并希望将任何以'\'结尾的行视为继续到下一行,即合并它们。下面的递归代码可以实现,但必须有一些聪明的方法,类似于mapfilter和所有?

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

2 个答案:

答案 0 :(得分: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

它可能不是最有效的方式(适用于小型列表,但不适用于大型列表),因为它使用不可变数据结构,更有效的方法是使用可变列表。

答案 1 :(得分: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)
  }