【问题标题】:Scala: how to make a Hash(Trie)Map from a Map (via Anorm in Play)Scala:如何从 Map 制作 Hash(Trie)Map(通过 Anorm in Play)
【发布时间】:2013-01-19 04:05:22
【问题描述】:

HashTrieMapsdocs.scala-lang.org 上阅读此报价:

例如,要在地图中找到给定的键,首先要获取该键的哈希码。然后,哈希码的最低 5 位用于选择第一个子树,然后是接下来的 5 位,以此类推。一旦存储在节点中的所有元素的哈希码在此级别之前选择的位中彼此不同,选择就会停止。

我认为这是一个很棒的(阅读:快!)集合来存储我的 Map[String, Long]。

在我的 Play Framework(使用 Scala)中,我使用 Anorm 加载了大约 18k 个元素的这段代码。加载需要几秒钟(没什么大不了的,但有什么提示吗?)。我想把它放在“内存中”,以便快速查找字符串到长的翻译。

val data = DB.withConnection { implicit c ⇒
  SQL( "SELECT stringType, longType FROM table ORDER BY stringType;" )
    .as( get[String]( "stringType" ) ~ get[Long]( "longType " )
    map { case ( s ~ l ) ⇒ s -> l }* ).toMap.withDefaultValue( -1L )
}

此代码使data 类型为class scala.collection.immutable.Map$WithDefault。我希望这是HashTrieMap 类型(或HashMap,因为我理解链接引用所有Scala HashMaps 都是HashTrieMap?)。奇怪的是,我找不到如何将其转换为 HashTrieMap 的方法。 (我是 Scala、Play 和 Anorm 的新手。)

// Test for the repl (2.9.1.final). Map[String, Long]:
val data = Map( "Hello" -> 1L, "world" -> 2L ).withDefaultValue ( -1L )
data: scala.collection.immutable.Map[java.lang.String,Long] =
  Map(Hello -> 1, world -> 2)

// Google showed me this, but it is still a Map[String, Long].
val hm = scala.collection.immutable.HashMap( data.toArray: _* ).withDefaultValue( -1L )

// This generates an error.
val htm = scala.collection.immutable.HashTrieMap( data.toArray: _* ).withDefaultValue( -1L )

所以我的问题是如何将 MapWithDefault 转换为 HashTrieMap(或 HashMap,如果共享 HashTrieMap 的实现)?

欢迎任何反馈。

【问题讨论】:

    标签: scala playframework anorm


    【解决方案1】:

    正如您所指的文档所解释的,不可变映射已经在后台实现为HashTrieMaps。您可以在 REPL 中轻松验证这一点:

    scala> println( Map(1->"one", 2->"two", 3->"three", 4->"four", 5->"five").getClass )
    class scala.collection.immutable.HashMap$HashTrieMap
    

    所以你没有什么特别的事情要做,你的代码已经在使用HashMap.HashTrieMap,而你甚至没有意识到。

    更准确地说,immutable.Map 的默认实现是immutable.HashMap,由immutable.HashMap.HashTrieMap 进一步细化(扩展)。 请注意,虽然小的不可变映射 不是 immutable.HashMap.HashTrieMap 的实例,但被实现为特殊情况(这是一种优化)。有一个特定的大小阈值,它们开始被执行为immutable.HashMap.HashTrieMap。 例如,在 REPL 中输入以下内容:

    val m0 = HashMap[Int,String]()
    val m1 = m0 + (1 -> "one")
    val m2 = m1 + (2 -> "two")
    val m3 = m2 + (3 -> "three")
    println(s"m0: ${m0.getClass.getSimpleName}, m1: ${m1.getClass.getSimpleName}, m2: ${m2.getClass.getSimpleName}, m3: ${m3.getClass.getSimpleName}")
    

    将打印这个:

    m0: EmptyHashMap$, m1: HashMap1, m2: HashTrieMap, m3: HashTrieMap
    

    所以这里的空地图是EmptyHashMap$ 的一个实例。添加一个元素会得到HashMap1,再添加一个元素最终会得到HashTrieMap


    最后,withDefaultValue 的使用不会改变任何事情,因为withDefaultValue 只会返回一个实例Map.WithDefault,它会包装初始映射(仍将是HashMap.HashTrieMap)。

    【讨论】:

    • 在最近的 scala 版本中,这个(不可变映射已经在底层实现为 HashTrieMaps)改变了吗?我现在使用 Scala 2.11.8 REPL 为您拥有的第一个代码 sn-p 得到了其他东西:class scala.collection.mutable.HashMap
    • 你确定吗?因为我刚刚在 2.11.8 REPL 中尝试过并得到完全相同的结果。如果您没有使用可变 Map 尝试过,您可能会再次检查。你做过import scala.collection.mutable._之类的事情吗?如果是这样,那么在执行 Map(1->"one", 2->"two", 3->"three", 4->"four", 5->"five") 时,您实际上是在实例化一个可变 Map 并打印其类确实会导致 "class scala.collection.mutable.HashMap"
    猜你喜欢
    • 2011-08-01
    • 2021-05-01
    • 2018-06-04
    • 2021-05-30
    • 1970-01-01
    • 2016-09-29
    • 1970-01-01
    • 2013-05-11
    相关资源
    最近更新 更多