I've been trying to enhance my knowledge with scala. I am trying to implement this function recursively but having difficulty.
My main question IS, how can you accept a list in the parameter that accepts either a list or numbers.
depth(x: Any): Int is the signature you want, then pattern match on x to determine if it's a List[_] or not, where _ indicates you don't care what's in the list. (Using Seq[_] would be the more idiomatic Scala type to use, actually.) Note that the example shown is missing a pair of parens, List(1, 2, List(3))... It also assumes that depth(8) == 0 (for example).
A tricky part is that you shouldn't assume that a nested list will either be the first or last element in the "parent" list, i.e., ...List(1,List(2,3),4)... is possible.
A final bit worth mentioning; if you were building a "production" depth method, it would be worth having a Tree abstraction with Node and Leaf concrete types so you can use a better type signature, depth(tree: Tree[_]): Int, to make it explicitly clear when something represents part of the tree structure vs. data in the tree. Using List here is convenient for the exercise, but a bit ambiguous otherwise, since you could have a tree of stuff where some nodes are actually lists.
collect is handy here:
def depth(xs: List[Any]): Int =
1 + xs.collect{case xs: List[_] => depth(xs)}
.foldLeft(0)(_ max _)
P.S. I agree with Dean's comments about the type List[Any] being a poor way to represent trees. List[Any] is a type that should never appear in ordinary Scala code, so I'm sad to see it used in an exercise intended for beginners.
If you are insisting on using for comprehension, I can provide implementation that works with it.
First you define two useful classes
import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.Builder
class Folder[T](init : T, step : (T,T) => T) extends Builder[T,T] {
private[this] var state = init
override def += (elem : T) = {
state = step(state, elem)
this
}
override def clear() {
state = init
}
override def result() : T = state
}
class CanBuildFolder[F,T](init : T, step : (T,T) => T) extends CanBuildFrom[F,T,T] {
override def apply() : Builder[T,T] = new Folder(init, step)
override def apply(from : F) : Builder[T,T] = new Folder(init, step)
}
than you can use them with the for comprehension
import scala.math.max
object Test {
val example = List(1, List(2, 3), List( List(4, 5), 6, List(7, List(List(8), 9))))
implicit val maxFolder = new CanBuildFolder[List[Any], Int](0, max)
def depth(source : List[Any]) : Int =
for (x <- source) yield x match {
case l : List[Any] => depth(l) + 1
case _ => 1
}
assert(depth(example) == 5)
}
List[Any]would go.for (i <- l) {}gives youUnitand notIntas you intended. To take results out fromforexpression you need toyieldthemfor {x <- collection} f(x)is syntax sugar for theforeachfunction in scala-lang.org/files/archive/nightly/docs/library/… . Its signature isdef foreach[U](f: (A) ⇒ U): Unit. So it returnsUnitbut you need to getIntsomehow