如何在 Scala 中更新不可变树图中的键值

How to update value of a key in a immutable tree map in Scala

我使用的是 Scala 2.11,我正在尝试更新树图中某个键的值。我尝试使用更新:

private val xyz = List(0, 100000, 500000, 1000000)
private val abc = List (0, 5, 25, 50)
private var a = TreeMap.empty[Int, TreeMap[Int, Int]] ++ xyz.map { 
        aa => aa -> (TreeMap.empty[Int, Int] ++ abc.map(bb => bb -> 0))
    }
a(xyz(0)).foreach { 
        case (key, value) =>
            if (key < 50) {
                a(xyz(0)) = a(xyz(0)).updated(key, 5)
            }
    }

得到错误:

 value update is not a member of scala.collection.immutable.TreeMap[Int,scala.collection.immutable.TreeMap[Int,Int]]

可以更新吗?或者有人可以帮助我使用 Java 树图复制逻辑,因为这也将允许我使用 floorEntry 和 ceilingEntry 函数。我尝试转换为 java 树状图,它生成了一个规则图,而不是树状图:

private var a = TreeMap.empty[Int, TreeMap[Int, Int]] ++ xyz.map { 
    aa => aa -> (TreeMap.empty[Int, Int] ++ abc.map(bb => bb -> 0)).asJava
}
private var b = a.asJava

您对 var/valmutable/immutable 感到困惑。

我认为您正确理解了valvar之间的区别,前者是不可变变量,后者是可变变量。即,如果您尝试重新分配分配为 val 的对象,您将收到错误消息。

import scala.collection.immutable.TreeMap

val tm = TreeMap(1 -> 1, 2 -> 2, 3 -> 3)
tm = TreeMap(1->2)
      ^
   error: reassignment to val

但是一个var可以变异:

import scala.collection.immutable.TreeMap

var tm = TreeMap(1 -> 1, 2 -> 2, 3 -> 3)
tm = TreeMap(1->2)
// mutated tm

请注意,在后一种情况下,即使我们改变了变量,我们也没有改变集合本身,我们分配了一个新的 TreeMap。因为我们使用 scala.collection.immutable.TreeMap 它不能被改变。

相反,如果我们使用 scala.collection.mutable.TreeMap,它有一个 update 函数

import scala.collection.mutable.TreeMap

val tm = TreeMap(1 -> 1, 2 -> 2, 3 -> 3)
tm.update(1, 5)
tm //TreeMap(1 -> 5, 2 -> 2, 3 -> 3)

scala.collection.immutable.TreeMap 更改为 scala.collection.mutable.TreeMap 后,这将起作用

a(xyz(0)).foreach{ case (key, value) =>
  if(key < 50){
    a(xyz(0)) = a(xyz(0)).updated(key, 5) //addOne(key, 5) if 2.13+
  }
}

编辑 使用 java.util.TreeMap

 private val xyz = List(0, 100000, 500000, 1000000)
 private val abc = List(0, 5, 25, 50)

 import java.util.{TreeMap => JTreeMap}

 val jTreeMap = xyz.foldLeft(new JTreeMap[Int, JTreeMap[Int, Int]]()) { (acc, elem) =>
   acc.put(
     elem,
     abc.foldLeft(new JTreeMap[Int, Int]()) { (acc2, elem2) =>
       acc2.put(elem2, 0)
       acc2
     }
   )
   acc
 }
 //Map created

 jTreeMap.get(xyz.head).replaceAll{
   //hack for scala 2.11.x
   new java.util.function.BiFunction[Int, Int, Int]{
     def apply(key: Int, value: Int) = if (value < 5) 5 else value
   }
 }
 //value edited

无法更新不可变对象,您只能从旧对象创建新的不可变对象。因此,代码需要根据需要从具有不同值的原始代码创建一个新的 TreeMap

代码如下所示:

val newMap = a.map{
  case (k, v) if k == xyz(0) =>
    k -> v.map {
      case (k2, v2) if k2 < 50 =>
        k2 -> 5
      case (k2, v2) =>
        k2 -> v2
    }
  case (k, v) =>
    k -> v
}

这分解为在外部 TreeMap 中查找匹配键的外部 map 和在内部 [=11= 中查找匹配键的内部 map ].模式匹配(case)用于实现匹配测试,也用于提取键和值。

每个 map 都有一个 case 用于选择要修改的值,而第二种情况则保留其他值不变。第一种情况 returns 具有修改值的原始密钥,而第二种情况只是 returns 原始值 (k -> v).


另请注意,var 适用于变量,而不是变量的内容。它指示变量是否可以更新以引用不同的对象,但没有说明变量引用的对象是否可以更新。 var 在 Scala 中很少使用,因为它违背了简洁的功能设计。