Reputation: 361
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.
Upvotes: 0
Views: 152
Reputation: 30453
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.
Upvotes: 1
Reputation: 8996
I will try to answer this by giving a shot on the recursive solution:
def depth(listOrNum: Any): Int = {
def help(y: Any, c: Int): Int = {
y match {
case y: Int => c
case List(curHead, rest @ _*) =>
Math.max(help(curHead, c+1), help(rest, c))
case _ => 0
}
}
help(listOrNum, 0)
}
Upvotes: 1
Reputation: 5977
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)
}
Upvotes: 0
Reputation: 2151
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.
Upvotes: 3