什么更新继承的PrefixMap Map?

时间:2017-12-01 17:09:09

标签: scala scala-collections

从Scala集合体系结构第3版“Scala编程”一书中运行PrefixMap示例,我不明白在调用update时更新继承的PrefixMap Map。 这是代码:

import collection._

class PrefixMap[T]
  extends mutable.Map[String, T]
    with mutable.MapLike[String, T, PrefixMap[T]] {

  val id: Long = PrefixMap.nextId
  var suffixes: immutable.Map[Char, PrefixMap[T]] = Map.empty
  var value: Option[T] = None

  def get(s: String): Option[T] =
    if (s.isEmpty) value
    else suffixes get s(0) flatMap (_.get(s substring 1))

  def withPrefix(s: String): PrefixMap[T] =
    if (s.isEmpty) this
    else {
      val leading = s(0)
      suffixes get leading match {
        case None =>
          suffixes = suffixes + (leading -> empty)
        case _ =>
      }
      val ret = suffixes(leading) withPrefix (s substring 1)
      println("withPrefix: ends with: id="+this.id+", size="+this.size+", this="+this)
      ret
    }

  override def update(s: String, elem: T) = {
    println("update: this before withPrefix: id="+this.id+", size="+this.size+", return="+this)
    val pm = withPrefix(s)
    println("update: withPrefix returned to update: id="+pm.id+", size="+pm.size+", return="+pm)
    println("===> update: this after withPrefix and before assignment to pm.value : id="+this.id+", size="+this.size+", return="+this)
    pm.value = Some(elem)
    println("===> update: this after assinment to pm.value: id="+this.id+", size="+this.size+", return="+this)
  }

  override def remove(s: String): Option[T] =
    if (s.isEmpty) { val prev = value; value = None; prev }
    else suffixes get s(0) flatMap (_.remove(s substring 1))

  def iterator: Iterator[(String, T)] =
    (for (v <- value.iterator) yield ("", v)) ++
      (for ((chr, m) <- suffixes.iterator;
            (s, v) <- m.iterator) yield (chr +: s, v))

  def += (kv: (String, T)): this.type = { update(kv._1, kv._2); this }

  def -= (s: String): this.type  = { remove(s); this }

  override def empty = new PrefixMap[T]
}

object PrefixMap {
  var ids: Long = 0
  def nextId: Long = { PrefixMap.ids+=1; ids }
}

object MyApp extends App {
  val pm = new PrefixMap[Int]
  pm.update("a", 0)
  println(pm)

}

输出结果为:

更新:这在withPrefix之前:id = 1,size = 0,return = Map()

withPrefix:以:id = 1,size = 0,this = Map()

结束

更新:withPrefix返回更新:id = 2,size = 0,return = Map()

===&GT;更新:这是在withPrefix之后和赋值给pm.value之前:id = 1,size = 0,return = Map()

===&GT;更新:这是对pm.value的暗示:id = 1,size = 1,return = Map(a - &gt; 0)

地图(a - &gt; 0)

所以问题是:更新方法中带有“pm.value = Some(elem)”的行怎么可能导致继承的PrefixMap Map用(a - &gt; 0)更新?

1 个答案:

答案 0 :(得分:2)

继承 PrefixMap地图”的含义尚不清楚。 Maptrait,如果您来自Java世界,则类似于interface。这意味着Map本身并不具有任何价值,它只是指定契约,并通过“核心”方法(您在PrefixMap中实现的方法)提供各种便捷方法的默认实现。

至于整个数据结构的工作原理,您应该将此PrefixMap实现假设为"tree"。逻辑上,每个边都有一个char(在前缀序列中),每个节点可能是一个值,该值对应于通过在从根到当前节点的路上累积所有字符而创建的字符串。

因此,如果您有一个带有"ab" -> 12键值的Map,那么树将如下所示: ab tree

如果您将"ac" -> 123添加到树中,它将变为

ab+ac tree

最后,如果您将"a" -> 1添加到树中,它将变为:

a+ab+ac tree

这里重要的观察是,如果你将“a”节点作为根,你将留下的是一个有效的前缀树,所有字符串都用“a”前缀缩短。

在物理上,布局有点不同:

  1. 根节点是PrefixMap[T],它是来自外部的Map[String,T],也是一个空字符串密钥的节点。
  2. value + suffixes的内部节点,即子节点的可选值和合并列表,其边缘对应的字符为Map[Char, PrefixMap[T]]
  3. 正如您所看到的,update实施有效地找到withPrefix调用的内容,然后为其分配值。那么withPrefix方法的作用是什么?虽然它是递归实现的,但是以迭代的方式思考它可能更容易。从这个角度来看,它逐个遍历给定String的字符,并在树中导航,创建缺少的节点,参见

     case None =>
          suffixes = suffixes + (leading -> empty)
    

    并最终返回与整个String对应的节点(即this,以防最深的递归s.isEmpty

    方法get实现实际上与withPrefix非常相似:它递归地迭代给定的字符串并在树中导航,但它更简单,因为它不必创建缺少的节点。由于子节点实际上也存储在Map get方法中,Option方法返回PrefixMap的方式与Option应返回flatMap的方式相同。所以你可以使用iterator,如果在某个级别没有这样的子节点,它将正常工作。

    最后value.iterator将其迭代器创建为

    的并集
    1. Option(幸运的是,Scala iterator实现了iterator,只返回1或0个元素,具体取决于是否有值)
    2. 所有子节点的所有val pm = new PrefixMap[Int] pm.update("a", 0) println(pm) 只是添加自己的字符作为其键的前缀。
    3. 所以当你这样做时

      update

      pm.toString创建树中的节点并存储该值。 iterate实际上使用value来构建字符串表示。因此,它会在树集合中迭代所有节点中非空Option List<?> chatList = chatService.limitedChatResult(eventStatus.getFlexiObject().getId(), 10, 10); getLogger().info("chatList: " + chatList.size()); def sortedMap = [:]; List<Chat> dayChatEntries = null; SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy"); int x = 0; getLogger().info("sortedMap before starting the loop: map --> " + sortedMap); for(Chat chat: chatList){ String day = sdf.format(chat.getLastWrite()); if (sortedMap.containsKey(day)) { getLogger().info(x + " day: " + day); getLogger().info("sortedMap: " + sortedMap); //I can not print the map at this position getLogger().info("sortedMap key: " + sortedMap[day]); sortedMap.get(day).add(chat); getLogger().info("a new chat object was added to map list"); } else { getLogger().info(x + " day is not in the map: " + day); dayChatEntries = new ArrayList<Chat>(); dayChatEntries.add(chat); sortedMap.put(day, dayChatEntries); getLogger().info("The day has been added! "); } x++; } 的所有值。