如何根据Scala中的某些条件计算值

时间:2016-05-14 11:27:00

标签: scala if-statement immutability tail-recursion

我已经实现了一个递归方法来检查字符串中的括号数是否有效。这是代码

def balance(chars: List[Char]): Boolean = {
    @tailrec
    def isValid(newChars: List[Char], difference: Int): Boolean = {
      if (newChars.isEmpty) difference == 0
      else if (difference < 0) false
      else {
        var newDifference = difference // Scala IDE gives warning here

        if (newChars.head == '(') newDifference = difference + 1
        else if (newChars.head == ')') newDifference = difference - 1

        isValid(newChars.tail, newDifference)
      }
    }

    isValid(chars, 0)
}

我为以下测试用例测试了上面的代码并且工作正常所以我只是在寻找改进if / else梯形图。

println("Testing parenthesis balancing")
assert(balance("(Sachin is learning (scala) and (spark))".toList))
assert(!balance("(Invalid))(expression)".toList))
assert(balance("".toList))
assert(balance("()()".toList))
assert(!balance("{())}{()}".toList))

如代码中所述,Scala IDE在该行上抱怨说

  

避免可变局部变量

我不确定如何在不使用if / else的情况下计算newDifference的值。我能看到的其他选项是在if / else梯形图中直接调用isValid方法,并计算newDifference的值。

我还在学习Scala所以我想知道在不改变局部变量(或任何其他警告)的情况下编写此代码的最佳方法是什么。

2 个答案:

答案 0 :(得分:3)

人们使用模式匹配。这样你可以避免使用可变变量和“if / else梯形图”,这会产生可怕的“意大利面条代码”。

   def isValid(chars: List[Char], ps: Int = 0) = (chars, ps) match {
      case (Nil, _) => ps == 0
      case (_, _) if ps < 0 => false
      case ('(' :: tail, ps) => isValid(tail, ps + 1)
      case (')' :: tail, ps) => isValid(tail, ps - 1)
      case (_ :: tail, ps) => isValid(tail, ps)
   }

答案 1 :(得分:2)

你可以写:

val newDifference =
  if (newChars.head == '(') difference + 1
  else if (newChars.head == ')') difference - 1
  else difference;

因为Scala中的if是一个表达式,或者使用match,在这种情况下会被认为更惯用:

val newDifference = newChars.head match {
  case '(' => difference + 1
  case ')' => difference - 1
  case _   => difference
}

整个功能可以在match上转换为单个newChars,但我会留给您。有关一些想法,请参阅第一个示例here