roy
roy

Reputation: 361

functional programming with scala

I've been trying to enhance my knowledge with scala. I am trying to implement this function recursively but having difficulty.

enter image description here

My main question IS, how can you accept a list in the parameter that accepts either a list or numbers.

Upvotes: 0

Views: 152

Answers (4)

Seth Tisue
Seth Tisue

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

marios
marios

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

ayvango
ayvango

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

Dean Wampler
Dean Wampler

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

Related Questions