【问题标题】:scala concatenate string inside a list conditionallyscala有条件地连接列表中的字符串
【发布时间】:2016-10-04 12:18:10
【问题描述】:

案例1:给定一个Scala字符串列表

val l =List("@description", "AC", "T", "G", "+", "ZZZZ")

有什么好办法拼接"AC", "T", "G",预期的结果是

List("@description", "ACTG", "+", "ZZZZ")

规则是从第二个元素开始,所有字符串都应该连接起来,直到遇到另一个以+ 开头的字符串。鉴于序列行可以被包装,它与FASTQ 格式解析有关。该功能预计是功能性的(又名纯)。我认为它可以用foldLeft 来实现。

更新:感谢您的回答!但是我意识到问题有点复杂,以下情况应该也可以工作

案例2,输入:

val l = List("@desc", "AA", "T", "+foo", "XX", "X", "@desc2", "TT", "C", "+bar", "Y", "YY")

预期输出:

List("@desc", "AAT", "+foo", "XXX", "@desc2", "TTC", "+bar", "YYY")

因此列表中可以有多个 FASTQ 记录。在上述情况下,有两个。描述行必须以 @ 开头。

案例3:

输入:

val l = List("@desc", "AAA", "TTT", "+foo", "@desc", "X", "@desc2", "TT", "C", "+bar", "+", "YY")

预期输出:

List("@desc", "AAATTT", "+foo", "@descX", "@desc2", "TTC", "+bar", "+YY")

这是三个中最具挑战性的案例,因为质量行(即第一行之后以“+”开头的行)也可以以 @ 或 + 开头。例如“@desc”实际上是质量的一部分,而不是另一条记录的起跑线。区分描述行和质量行的方法可能是序列行的长度和质量行的长度必须匹配。在第三种情况下,例如"AAATTT".length === "@descX".length,还有"TTC".length == "+YY".length

【问题讨论】:

  • 在情况 3 中,不明确的质量线是否总是分为 2 段?
  • 还有多少个带有+的字符串在换行之前?

标签: scala


【解决方案1】:
  val l = List("@description", "AC", "T", "G", "+", "ZZZZ")
  val (prefix, suffix) = l.tail span (!_.startsWith("+"))
  val result = l.head :: prefix.mkString :: suffix

【讨论】:

    【解决方案2】:

    试试这个:

    list.span(!_.startsWith("+")) match {
      case (x::xs, rest) => x :: xs.mkString :: rest
      case (_, rest) => rest
    }
    

    【讨论】:

    • 你能解释一下第二种情况的作用吗?
    • span 的 list 左侧部分为空时需要第二种情况,因此它的模式与 x::xs 不匹配。没有第二部分,空列表是不安全的
    【解决方案3】:

    只是想添加一个使用经常被遗忘的span 函数的答案,这也相当有效。

    def conditionalConcat(strings: List[String]): List[String] = strings match {
      case Nil => Nil
      case head :: tail => head :: {
        val (beforePlus, afterPlus) = tail.span(!_.startsWith("+"))
        beforePlus.mkString :: afterPlus
      }
    }
    

    你可以在ScalaFiddle试试看

    【讨论】:

    • +: 和:: 有什么区别?看完doc我还是不确定
    • +: 是一种适用于所有SeqLike 对象的方法,而:: 特定于List。两者都前置,但使用 :: 应该保证 O(1) 复杂性,而 +: 没有。这很有帮助,因为在重构时,您想知道是否有可能失去该保证。
    【解决方案4】:

    当然可以使用foldLeft 完成,但我认为这可能会比以下更复杂。

    def limitedConcat(ss: List[String]): List[String] = {
      val idx = ss.indexWhere(_.startsWith("+"))
      if (idx < 2) ss
      else ss.head :: ss.slice(1, idx).mkString :: ss.drop(idx)
    }
    

    如果列表为空,如果没有 "+" 元素,以及由于某种原因,"+" 元素出现得太早,这应该可以工作。

    【讨论】:

      【解决方案5】:

      我认为以下两个功能可以适用于所有三种情况,我认为它们可以适当重构以看起来更好

      def extractQual(input: List[String], seqLength: Int, qual: String = ""): (String, List[String]) = {
          if (qual.length == seqLength) (qual, input)
          else if (qual.length > seqLength) ("", List())
          else extractQual(input.tail, seqLength, input.head + qual)
        }
      
      def cleanFastqLines(lines: List[String], result: List[String] = List()): List[String] = lines match {
          case desc :: Nil => Nil
          case desc :: tail => {
            val (beforePlus, rest) = tail.span(_.head != '+')
            val seq = beforePlus.mkString
            val altDesc = rest.head
            val (qual, remained) = extractQual(rest.tail, seq.length)
            if (remained.nonEmpty) List(desc, seq, altDesc, qual) ::: cleanFastqLines(remained, result) ::: result
            else List(desc, seq, altDesc, qual) ::: result
          }
        }
      

      【讨论】:

        猜你喜欢
        • 2015-01-01
        • 1970-01-01
        • 2022-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-24
        相关资源
        最近更新 更多