分隔符之间的Seq / Array中的Scala过滤器元素

时间:2017-07-24 20:06:30

标签: arrays scala list filter

我有一个数组如:

val array = Array("Hello", "```", "blabla", "anything", "filler", "```", "another filler")

filter方法仅适用于数组的每个元素或Seq

array.filter(s => !s.startsWith("```"))
> Array(Hello, blabla, anything, filler, another filler)

我想删除分隔符"```"之间的任何内容。最终结果将是

Array("Hello", "another filler")

问题类似于Bracket coding task solved by a Stack。 你怎么能在纯FP中完成这个?

另外

分隔符"```"分隔了2个部分。

注意:分隔符不相等,但以"```"开头。有一个"```scala"

val input = Array("Hello", "```", "blabla1", "```", "blabla2", "```scala","blabla3", "filler", "```", "blabla4")

filteredOutput =  Array("Hello", "blabla2", "blabla4")

PS:也许你想通了,该解决方案会从降价文件中过滤出代码注释。

3 个答案:

答案 0 :(得分:2)

这应符合您的更新要求。

def condense(ss: Seq[String], delimiter: String): Seq[String] = {
  val start = ss.indexWhere(_.startsWith(delimiter))
  val stop  = ss.indexWhere(_.startsWith(delimiter), start + 1)
  if (stop < 0) ss
  else condense(ss.patch(start, Seq(), stop-start+1), delimiter)
}

condense(input, "```")  // res0: Array[String] = Array(Hello, blabla2, blabla4)

答案 1 :(得分:1)

我不确定这是否是最好的方式,但我提出的一种方法是折叠它:

val (filteredOutput: Array[String], _) =
  input.foldLeft((Array[String](), true)) {
    case ((output: Array[String], include: Boolean), sep) if sep.startsWith("```") => (output, !include)
    case ((output: Array[String], true), next: String) => (output :+ next, true)
    case ((output: Array[String], false), _) => (output, false)
  }

这是一个更新版本,应该处理有关奇数个分隔符的更新要求:

val filteredOutput = {
  val (workingOutput: Array[String], _, discard: List[String]) =
    input.foldLeft((Array[String](), true, List[String]())) {
      case ((output: Array[String], include: Boolean, _), sep) if sep.startsWith("```") =>
        (output, !include, if (include) List(sep) else Nil)

      case ((output: Array[String], true, _), next: String) =>
        (output :+ next, true, Nil)
      case ((output: Array[String], false, discard: List[String]), next: String) =>
        (output, false, next :: discard)
    }
  workingOutput ++ discard.reverse
}

答案 2 :(得分:1)

另一个版本,避免使用索引:

val input = Array("Hello", "```", "blabla1", "```",
                  "blabla2", "```scala", "blabla3", "filler", "```", "blabla4")

def condense(xs: Array[String], acc: Array[String] = Array()): Array[String] = {
  if (xs.isEmpty) acc
  else {
    val (before, after) = xs.span(!_.startsWith("```"))
    val remaining = after.drop(1).dropWhile(!_.startsWith("```"))
    if (remaining.isEmpty) // unclosed commment
      acc ++ xs
    else condense(remaining.drop(1), acc ++ before)
  }
} 

condense(input) //> res0: Array[String] = Array(Hello, blabla2, blabla4)