scala有条件地在列表中连接字符串

时间:2016-10-01 00:44:41

标签: scala

Case1 :给定一个字符串的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")

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

5 个答案:

答案 0 :(得分:1)

当然可以使用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)
}

如果列表为空,如果没有"+"元素,并且由于某种原因,"+"元素显示得太早,这应该有用。

答案 1 :(得分:1)

  val l = List("@description", "AC", "T", "G", "+", "ZZZZ")
  val (prefix, suffix) = l.tail span (!_.startsWith("+"))
  val result = l.head :: prefix.mkString :: suffix

答案 2 :(得分:1)

只是想添加一个使用经常遗忘的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

中试用

答案 3 :(得分:1)

试试这个:

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

答案 4 :(得分:0)

我认为这三个案例都适用于以下两个函数,我认为它们可以正确地重构以便更好看

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