16

私はscalaから始めて、それに機能的な方法を適用しようとしていますが、読みにくいネストされたif \ else構造がたくさん出てきました。そのようなものをプログラムするための、より良い方法があるのでしょうか。

たとえば、括弧のバランスをとるスクリプトを作成しました。

def balance(chars: List[Char]): Boolean = {
    def checkParentesys(chars: List[Char], parentesis: List[Char]): Boolean =
      if (chars.isEmpty && parentesis.isEmpty)
        true
      else
        if (chars.head == '(')
            checkParentesys(chars.tail, '(' :: parentesis)
        else
            if (parentesis.isEmpty)
                false
            else
                checkParentesys(chars.tail, parentesis.tail)

    checkParentesys(chars.filter(s => s == '(' || s == ')'), List())
  }

より機能的でスカラのように書くにはどうすればよいですか?

4

4 に答える 4

27

折り目として書く方が良いかもしれません:

def balance(chars: List[Char]): Boolean = chars.foldLeft(0){
  case (0, ')') => return false
  case (x, ')') => x - 1
  case (x, '(') => x + 1
  case (x, _  ) => x
} == 0
于 2012-09-21T05:30:49.030 に答える
19

リストをトラバースする前にリストをフィルタリングする理由はないと思います。リストをトラバースするときは、括弧以外は無視してかまいません。2番目のリストを作成する必要もないと思います。本当に知りたいのは、開き括弧の数が決して負になることはないということです。

def balance(chars: List[Char]): Boolean = {
  @tailrec
  def _balance(chars: List[Char], count: Int) : Boolean = 
    chars match {
        case Nil => count == 0   // end of the string did we close every open?
        case '(' :: xs => _balance(xs, count+1)  
        case ')' :: xs => (count > 0) && _balance(xs, count-1) 
        case _ => _balance(chars.tail, count) // uninteresting char, skip it
    }

  _balance(chars, 0)
}
于 2012-09-21T03:59:06.297 に答える
4

上手:

  1. あなたはそれを条件付きで書くことから始めることができelse ifます。
  2. tailrec末尾再帰なので 、注釈を付けてください。
  3. フィルタ条件は、からSet('(', ')')の関数である、としてより簡単に記述できます。CharBoolean
  4. charsあなたは空であるがそうではないという条件を逃していると思いますparenthesis

したがって、次のようになります。

def balance(chars: List[Char]): Boolean = {
  @tailrec
  def checkParentesys(chars: List[Char], parentesis: List[Char]): Boolean =
    if (chars.isEmpty && parentesis.isEmpty)
      true
    else if (chars.head == '(')
      checkParentesys(chars.tail, '(' :: parentesis)
    else if (chars.isEmpty || parentesis.isEmpty)
      false
    else
      checkParentesys(chars.tail, parentesis.tail)

  checkParentesys(chars.filter(Set('(', ')')), List())
}

全体をパターンマッチに変えることもできます。

def balance(chars: List[Char]): Boolean = {
  @tailrec
  def checkParentesys(chars: List[Char], parentesis: List[Char]): Boolean =
    (chars, parentesis) match {
      case (Nil, Nil) => true
      case ('(' :: charsTail, _) => checkParentesys(charsTail, '(' :: parentesis)
      case (Nil, _) => false
      case (_, Nil) => false
      case (')' :: charsTail, '(' :: parentesisTail) => checkParentesys(charsTail, parentesisTail)
    }
  checkParentesys(chars.filter(Set('(', ')')), List())
}
于 2012-09-21T03:22:03.987 に答える
3
var parens :List[Char] =  Nil
def matcher(chrs: List[Char]): Boolean = {
     if (chrs.isEmpty) {
        return parens.isEmpty
     }
     else {
         chrs.head match {
           case '(' =>  parens = '(' :: parens ;matcher(chrs.tail)
           case ')' =>  if (parens.isEmpty) return false 
                            else if (parens.apply(0) ==  '(') parens = parens.drop(1) 
                            else return false;  
                            matcher(chrs.tail);
           case _ => matcher(chrs.tail)
         }
     }
}

ご覧のとおり、カウントが機能しないため、カウントは使用しませんでした())(

于 2012-09-26T19:42:03.493 に答える