简体   繁体   English

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

[英]Scala: how to make a Hash(Trie)Map from a Map (via Anorm in Play)

Having read this quote on HashTrieMaps on docs.scala-lang.org : 看了这个帖HashTrieMapsdocs.scala-lang.org

For instance, to find a given key in a map, one first takes the hash code of the key. 例如,要在地图中找到给定的密钥,首先要获取密钥的哈希码。 Then, the lowest 5 bits of the hash code are used to select the first subtree, followed by the next 5 bits and so on. 然后,哈希码的最低5位用于选择第一个子树,然后是接下来的5位,依此类推。 The selection stops once all elements stored in a node have hash codes that differ from each other in the bits that are selected up to this level. 一旦存储在节点中的所有元素具有在直到该级别选择的位中彼此不同的哈希码,则选择停止。

I figured that be a great (read: fast!) collection to store my Map[String, Long] in. 我认为这是一个很棒的(读取:快!)集合来存储我的Map [String,Long]。

In my Play Framework (using Scala) I have this piece of code using Anorm that loads in around 18k of elements. 在我的Play框架中(使用Scala)我使用Anorm加载了大约18k个元素的代码片段。 It takes a few seconds to load (no big deal, but any tips?). 加载需要几秒钟(没什么大不了的,但任何提示?)。 I'd like to have it 'in memory' for fast look ups for string to long translation. 我希望将它“存储在内存中”,以便快速查找字符串到长时间的翻译。

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 )
}

This code makes data of type class scala.collection.immutable.Map$WithDefault . 此代码生成类型为class scala.collection.immutable.Map$WithDefault data类型。 I'd like this to be of type HashTrieMap (or HashMap , as I understand the linked quote all Scala HashMaps are of HashTrieMap?). 我希望这是HashTrieMap类型(或HashMap ,因为我理解链接引用所有Scala HashMaps都是HashTrieMap?)。 Weirdly enough I found no way on how to convert it to a HashTrieMap. 奇怪的是,我没有找到如何将其转换为HashTrieMap的方法。 (I'm new to Scala, Play and Anorm.) (我是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 )

So my question is how to convert the MapWithDefault to HashTrieMap (or HashMap if that shares the implementation of HashTrieMap)? 所以我的问题是如何将MapWithDefault转换为HashTrieMap(或HashMap,如果它共享HashTrieMap的实现)?

Any feedback welcome. 任何反馈欢迎。

As the documentation that you pointed to explains, immutable maps already are implemented under the hood as HashTrieMap s. 正如您所指出的文档所解释的那样,不可变映射已经在HashTrieMap下实现。 You can easily verify this in the REPL: 您可以在REPL中轻松验证:

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

So you have nothing special to do, your code already is using HashMap.HashTrieMap without you even realizing. 所以你没有什么特别的事,你的代码已经在使用HashMap.HashTrieMap而你甚至没有意识到。

More precisely, the default implementation of immutable.Map is immutable.HashMap , which is further refined (extended) by immutable.HashMap.HashTrieMap . 更确切地说, immutable.Map的默认实现是immutable.HashMap ,它由immutable.HashMap.HashTrieMap进一步细化(扩展)。 Note though that small immutable maps are not instances of immutable.HashMap.HashTrieMap , but are implemented as special cases (this is an optimization). 请注意,虽然小的不可变映射不是 immutable.HashMap.HashTrieMap实例,但是作为特殊情况实现(这是一种优化)。 There is a certain size threshold where they start being impelmented as immutable.HashMap.HashTrieMap . 有一个特定的大小阈值,它们开始被强制为immutable.HashMap.HashTrieMap As an example, entering the following in the REPL: 例如,在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}")

will print this: 将打印此:

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

So here the empty map is an instance of EmptyHashMap$ . 所以这里的空映射是EmptyHashMap$一个实例。 Adding an element to that gives a HashMap1 , and adding yet another element finally gives a HashTrieMap . 添加一个元素给出一个HashMap1 ,并添加另一个元素最终给出一个HashTrieMap


Finally, the use of withDefaultValue does not change anything, as withDefaultValue will just return an instance Map.WithDefault wich wraps the initial map (which will still be a HashMap.HashTrieMap ). 最后,使用withDefaultValue不会改变任何东西,因为withDefaultValue将只返回一个实例Map.WithDefault包装了初始映射(它仍然是HashMap.HashTrieMap )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM