地图未在递归函数中添加条目

时间:2019-10-11 16:23:13

标签: scala recursion

我正在与scala一起使用,并希望创建一个具有函数的类,该函数将递归地添加到地图中。

class Index(val map: Map[String, String]) {

    def add(e: (String, String)): Index = {
        Index(map + (e._1 -> e._2))
    }

    def addAll(list: List[(String, String)], index: Index = Index()): Index = {
        list match {
            case ::(head, next) => addAll(next, add(head))
            case Nil => index
        }
    }
}

object Index {

    def apply(map: Map[String, String] = Map()) = {
        new Index(map)
    }
}


val index = Index()
val list = List(
  ("e1", "f1"),
  ("e2", "f2"),
  ("e3", "f3"),
)
val newIndex = index.addAll(list)
println(newIndex.map.size.toString())

由于该函数应该在地图上添加3个条目,所以我将这段代码打印为3,但实际输出为1。我做错了什么以及如何解决?

在线小提琴:https://scalafiddle.io/sf/eqSxPX9/0

2 个答案:

答案 0 :(得分:2)

在调用add(head)的地方应该发生index.add(head),这是一个简单的错误。

但是,在编写这样的递归例程时,最好使用嵌套方法,例如:

def addAll(list: List[(String, String)]): Index = {
  @annotation.tailrec
  def loop(rem: List[(String, String)], index: Index): Index = {
    rem match {
      case head :: tail => loop(tail, index.add(head))
      case Nil => index
    }
  }

  loop(list, Index())
}

这使函数可以进行尾部递归并由编译器进行优化,并且还避免了addAll方法的虚假参数。

答案 1 :(得分:1)

我看到您的代码有很多问题,但需要回答您的问题: 每次调用addAll时,都会创建一个带有空Map的索引。 在case ::(head, next) => addAll(next, add(head))行中,您没有使用从参数列表中获得的索引。那不应该以某种方式更新吗?

请注意,默认地图实现是不可变的,更新地图意味着您需要使用添加的新值创建一个新地图。