Scala:如何从地图制作哈希(Trie)地图(通过播放中的Anorm)

df'*_*df' 4 scala playframework anorm

看了这个帖HashTrieMapsdocs.scala-lang.org:

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

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

在我的Play框架中(使用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 )
}
Run Code Online (Sandbox Code Playgroud)

此代码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 )
Run Code Online (Sandbox Code Playgroud)

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

任何反馈欢迎.

Rég*_*les 9

正如您所指出的文档所解释的那样,不可变映射已经作为HashTrieMaps实现.您可以在REPL中轻松验证:

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

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

更确切地说,immutable.Map is 的默认实现,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}")
Run Code Online (Sandbox Code Playgroud)

将打印此:

m0: EmptyHashMap$, m1: HashMap1, m2: HashTrieMap, m3: HashTrieMap
Run Code Online (Sandbox Code Playgroud)

所以这里空地图是一个实例EmptyHashMap$.添加一个元素给出一个HashMap1,并添加另一个元素最终给出一个HashTrieMap.


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