简体   繁体   English

使用scala进行函数式编程

[英]functional programming with scala

I've been trying to enhance my knowledge with scala. 我一直在尝试通过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. depth(x: Any): Int是所需的签名,然后在x进行模式匹配以确定它是否为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). (实际上,使用Seq[_]将是更惯用的Scala类型。)请注意,所显示的示例缺少一对括号,即List(1, 2, List(3))...它还假定了depth(8) == 0 (例如)。

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, ie, ...List(1,List(2,3),4)... is possible. 一个棘手的部分是,您不应假设嵌套列表将成为“父”列表中的第一个元素或最后一个元素,即...List(1,List(2,3),4)...是可能的。

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. 如果您要构建“生产” depth方法,则值得使用NodeLeaf具体类型的Tree抽象,以便可以使用更好的类型签名depth(tree: Tree[_]): Int明确地使其实现当某些东西代表树结构的一部分与树中的数据时,请清除。 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. 在这里使用List对于练习很方便,但是在其他地方有点模棱两可,因为您可能拥有一棵树,其中有些节点实际上是列表。

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

collect is handy here: collect在这里很方便:

def depth(xs: List[Any]): Int =
  1 + xs.collect{case xs: List[_] => depth(xs)}
        .foldLeft(0)(_ max _)

PS I agree with Dean's comments about the type List[Any] being a poor way to represent trees. PS我同意Dean关于List[Any]类型表示树的糟糕方法的评论。 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. List[Any]是不应该出现在普通Scala代码类型,所以我很伤心看到它在供初学者练习使用。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM