2012-09-21 18 views
15

我開始與斯卡拉,並嘗試應用功能的方式,但我出來了一堆嵌套如果\其他結構很難閱讀,我不知道是否有更好的方式來編程這樣的事情? 例如,我已經寫了腳本,執行括號平衡斯卡拉的方式來編程一堆如果的

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

您能否提供,我怎麼能寫喜歡它更多的功能和更Scala呢?

+31

不要害羞,只是說這個問題是從斯卡拉的課程當然 – AndreasScheinert

+0

它是否有區別?我已經完成了任務,在提供的材料的範圍,並想知道更好的解決方案。 – Pilgrim

+5

它確實有所作爲,因爲您剛剛通過發佈答案違反了道德拉的榮譽法典(參見https://www.coursera.org/maestro/auth/normal/tos.php#honorcode規則3) – Frank

回答

25

這可能是更好的把它寫的一個方面:

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 
+0

港燈)的結果是短),謝謝,我很高興地看到所有這些選項,看起來像函數式編程是遠遠超過命令式編程 – Pilgrim

+2

我想用「迴歸」是壞的樣式選項? – Ilan

+2

並非總是如此。初學者,特別是來自Java的初學者,傾向於瘋狂地過度使用「返回」。但是,這裏'返回'是需要早日退出的。當然還有其他方法可以解決這個問題(請參閱其他答案),但這個對我來說似乎相當優雅,即使使用「return」也是如此。 –

3

好:

  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()) 
} 
+0

感謝Set和tailrec。所以,沒有辦法將其他邏輯重寫成更具可讀性。否則如果沒有多大幫助,因爲在我看來,如果它屬於並破壞邏輯,它就會迷惑。我以爲我可以結合多種方式來檢查一個表達式? – Pilgrim

+0

是的,我是這麼找,沒看到你的評論 – Pilgrim

+0

@Pilgrim的第二部分,我認爲,任何語言的大多數程序員會說,'別的if'是*更*可讀的,因爲它給讀者名單條件。此外,它絕對不*斷*邏輯;邏輯是相同的。 – dhg

17

我不認爲有任何理由來過濾在你遍歷它之前的列表。遍歷列表時,您可以忽略非圓括號。我認爲建立第二個清單也是沒有必要的。你真正想知道的是,左括號的數量從不爲負:

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) 
} 
+0

謝謝,這聽起來很合理 – Pilgrim

+2

而不是'_balance'使用'循環「或」去「或別的東西。首先是不符合非官方風格指南。 – sschaef

+0

的標準方法是調用它'balance0'我認爲 – ron

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

正如你可以看到我())(