函数式编程风格的过滤列表

dmi*_*747 3 functional-programming scala

我们有一个带有BEGIN和END标记的字符串列表作为此列表的一部分.我们可以在函数式编程风格中过滤出BEGIN-END之间的元素吗?我只是在scala中使用这种常规(标记)方法出来了.

val list1 =
  """992
  1010
  1005
  1112
  BEGIN
  1086
  1244
  1107
  1121
  END
  1223
  1312
  1319
  1306
  1469""".lines.toList

var flag = false
val filteredList = list1.filter{
  def f(x: String): Boolean = {
    if (x.contains("BEGIN")) {
      flag = true;
      return false
    } else if (x.contains("END")) {
      flag = false
    }
    flag
  }
  f
}
Run Code Online (Sandbox Code Playgroud)

这有可能避免定义标志变量吗?他们如何用纯函数式语言解决这个问题?

ten*_*shi 7

您可以使用drop/ tail,dropWhile,takeWhile功能:

val filteredList = list1.map(_.trim).dropWhile("BEGIN" !=).tail.takeWhile("END" !=)
Run Code Online (Sandbox Code Playgroud)

编辑

tail如果列表为空,注释中提到的将抛出异常,因此如果您希望保持安全,请使用drop(1)而不是tail:

val filteredList = list1.map(_.trim).dropWhile("BEGIN" !=).drop(1).takeWhile("END" !=)
Run Code Online (Sandbox Code Playgroud)

这是我的算法版本,它处理几个BEGINEND部分(一些疯狂的东西来自我 - 一个小状态机:)

var filteredList1 = list1.map(_.trim).foldLeft(List(None): List[Option[List[String]]]) {
  case (None :: rest, "BEGIN") => Some(Nil) :: rest
  case (Some(list) :: rest, "END") => None :: Some(list) :: rest
  case (Some(current) :: rest, num) => Some(num :: current) :: rest
  case (result, _) => result
}.flatten.reverse map (_.reverse)
Run Code Online (Sandbox Code Playgroud)

它返回 List[List[String]]

  • `drop(1)`在空列表中没有失败; `tail`呢.所以哪个是正确的取决于输入是坏的所需行为. (2认同)