Reputation: 2600
I am starting the Scala programming course on Coursera, coming from 2 years experience with Java/Python/C#.
I am working through a problem where you must check to see if a list of characters has balanced paranthesis.
/**
* Exercise 2
*/
def balance(chars: List[Char]): Boolean = {
def recursiveBalance(chars: List[Char]): Boolean = {
if (!chars.contains('(') && !chars.contains(')')) true
else {
val openIndex = chars.indexOf('(')
if (openIndex == -1) false
else {
val chars2 = dropFirstMatch(chars, '(')
val closeIndex = chars2.indexOf(')')
if(closeIndex == -1 || openIndex > closeIndex) false
else recursiveBalance(dropFirstMatch(chars2, ')'))
}
}
}
def remove(index: Int, list: List[Char]): List[Char] = {
list.take(index) ++ list.drop(index)
}
def dropFirstMatch[A](ls: List[A], value: A): List[A] = {
val index = ls.indexOf(value) //index is -1 if there is no match
if (index < 0) {
ls
} else if (index == 0) {
ls.tail
} else {
// splitAt keeps the matching element in the second group
val (a, b) = ls.splitAt(index)
a ++ b.tail
}
}
recursiveBalance(chars)
}
So this solution is working (if a little ugly). As part of the solution I attempted to remove an object from a list at a specific index. I've learned that in Scala Lists are immutable.
My attempt at doing this was to provide the index, the list, and use this example, which is the remove
function. This works in the REPL, I made a list, ran the function and a new list was returned without the specified index.
But this did not work in my balance
solution. Everytime the list was returned it was unchanged, causing infinite recursion. Eventually I stumbled on this article and borrowed their dropFirstMatch
function, and upon substituting it, bam, working solution.
I am very new to Scala, and I must be overlooking something - can someone point out what it might be?
Upvotes: 0
Views: 2125
Reputation: 40510
Checking for balanced parenthesis is way easier than what you are doing:
def balanced(list: Seq[Char]): Boolean = list.foldLeft(0) {
case (n, _) if (n < 0) => return false
case (n, '(') => n + 1
case (n, ')') => n - 1
case (n, _) => n
} == 0
Or, if you are a purist, like some commenters, and insist on recursion:
@tailrec
def balanced(chars: Seq[Char], n: Int = 0): Boolean = (n, chars) match {
case (-1, _) => false
case (n, Nil) => n == 0
case ('(' :: tail, n) => balanced(tail, n+1)
case (')' :: tail, n) => balanced(tail, n-1)
case (_ :: tail, n) => balanced(tail, n)
}
Upvotes: 2
Reputation: 1529
take(n)
selects the first n elements in your list, where drop(n)
selects all elements of the list except the first n ones.
To illustrate:
scala> val xs = List(0,1,2,3,4,5)
xs: List[Int] = List(0, 1, 2, 3, 4, 5)
scala> xs.take(2)
res0: List[Int] = List(0, 1)
scala> xs.drop(2)
res1: List[Int] = List(2, 3, 4, 5)
scala> xs.take(2) ++ xs.drop(2)
res2: List[Int] = List(0, 1, 2, 3, 4, 5)
In other words, your remove
function simply returns the same list because it take
s the first n elements of the original list, then adds that to the elements of the original list except the first n ones (drop
). In order to remove the element at the given index in your list, you merely need to increment the index by one in your call to drop:
def remove(index: Int, list: List[Char]): List[Char] = {
list.take(index) ++ list.drop(index+1)
}
Upvotes: 4