ListMap上的更新方法

时间:2015-11-19 19:04:40

标签: scala scala-collections

我正在使用ListMap,因为我需要保持插入顺序。初始化后,它似乎有效。但当我打电话给它更新时,订单搞砸了。 1-为什么? 2-是否还有其他MapLike没有出现此问题,如果没有,我应该如何更新地图而不会出现问题?

scala> import scala.collection.immutable.ListMap
import scala.collection.immutable.ListMap

scala> val a = ListMap(0 -> "A", 1 -> "B", 2 ->"C")
a: scala.collection.immutable.ListMap[Int,String] = Map(0 -> A, 1 -> B, 2 -> C)

scala> a.foreach(println)
(0,A)
(1,B)
(2,C)

scala> val b = a.updated(1, "D")
b: scala.collection.immutable.ListMap[Int,String] = Map(0 -> A, 2 -> C, 1 -> D)
scala> b.foreach(println)
(0,A)
(2,C)
(1,D)

2 个答案:

答案 0 :(得分:3)

我找不到任何存在的具有所需属性的不可变集合。但它可以手动制作。

import scala.collection.immutable.{IntMap, Map, MapLike} 

class OrderedMap[K, +V] private[OrderedMap](backing: Map[K, V], val order: IntMap[K], coorder: Map[K, Int], extSize: Int)
  extends Map[K, V] with MapLike[K, V, OrderedMap[K, V]] {
  def +[B1 >: V](kv: (K, B1)): OrderedMap[K, B1] = {
    val (k, v) = kv
    if (backing contains k)
      new OrderedMap(backing + kv, order, coorder, extSize)
    else new OrderedMap(backing + kv, order + (extSize -> k), coorder + (k -> extSize), extSize + 1)
  }
  def get(key: K): Option[V] = backing.get(key)

  def iterator: Iterator[(K, V)] = for (key <- order.valuesIterator) yield (key, backing(key))

  def -(key: K): OrderedMap[K, V] = if (backing contains key) {
    val index = coorder(key)
    new OrderedMap(backing - key, order - index, coorder - key, extSize)
  } else this

  override def empty: OrderedMap[K, V] = OrderedMap.empty[K, V]
}

object OrderedMap {
  def empty[K, V] = new OrderedMap[K, V](Map.empty, IntMap.empty, Map.empty, 0)

  def apply[K, V](assocs: (K, V)*): OrderedMap[K, V] = assocs.foldLeft(empty[K, V])(_ + _)
}

这里order是保留的插入顺序图(可能带有“洞”)。有效处理元素移除所需的coorder特殊字段。 extSize基本上是order.lastkey + 1,但更直接

现在您可以验证

val a = OrderedMap(0 -> "A", 1 -> "B", 2 -> "C")
a.foreach(println)  
val b = a.updated(1, "D")
b.foreach(println)

打印

(0,A)
(1,B)
(2,C)

(0,A)
(1,D)
(2,C)

答案 1 :(得分:1)

来自1->D

的scala文档
  

&#34;此方法允许用户创建带有附加映射的新地图   从关键到价值。&#34;

请注意,它没有说&#34;具有不同的现有密钥值&#34;。因此,当您使用1->C进行更新时,这是一个新的/额外的映射。因此它出现在列表的末尾,保留了插入顺序。旧映射{{1}}不再出现在地图中。

所以它没有&#34;搞砸了#34;这不是问题。它正在执行它记录的操作,映射按插入顺序排列。