paulmdavies
paulmdavies

Reputation: 1288

Scala Collection Specific Implementation

Say I have some data in a Seq in Scala 2.10.2, e.g:

scala> val data = Seq( 1, 2, 3, 4, 5 )
data: Seq[Int] = List(1, 2, 3, 4, 5)

Now, I perform some operations and convert it to a Map

scala> val pairs = data.map( i => i -> i * 2 )
pairs: Seq[(Int, Int)] = List((1,2), (2,4), (3,6), (4,8), (5,10))

scala> val pairMap = pairs.toMap
pairMap: scala.collection.immutable.Map[Int,Int] = Map(5 -> 10, 1 -> 2, 2 -> 4, 3 -> 6, 4 -> 8)

Now say, for performance reasons, I'd like pairMap to use the HashMap implementation of Map. What's the best way to achieve this?

Ways I've considered:

  1. Casting:

    pairMap.asInstanceOf[scala.collection.immutable.HashMap[Int,Int]]
    

    This seems a bit horrible.

  2. Manually converting:

    var hm = scala.collection.immutable.HashMap[Int,Int]()
    pairMap.foreach( p => hm += p )
    

    But this isn't very functional.

  3. Using the builder

    scala.collection.immutable.HashMap[Int,Int]( pairMap.toSeq:_* )
    

    This works, but it's not the most readable piece of code.

Is there a better way that I'm missing? If not, which of these is the best approach?

Upvotes: 0

Views: 101

Answers (2)

Beryllium
Beryllium

Reputation: 13008

You can combine

  • An explicit result type
  • map: Map key and value into a tuple
  • breakOut: "Break out" the sequence of tuples from map, and create the target type directly

like this

val s = Seq.range(1, 6)

val m: scala.collection.immutable.HashMap[Int, Int] = 
  s.map(n => (n, n * n))(scala.collection.breakOut)

which creates the HashMap on-the-fly without an intermediate map.

By using breakOut and the explicit result type an appropriate builder for map is chosen, and your target type is created directly

Upvotes: 0

Nate
Nate

Reputation: 2205

Interesting bit: it already is an immutable HashMap.

scala> val data = Seq( 1, 2, 3, 4, 5 )
data: Seq[Int] = List(1, 2, 3, 4, 5)

scala> val pairs = data.map( i => i -> i * 2 )
pairs: Seq[(Int, Int)] = List((1,2), (2,4), (3,6), (4,8), (5,10))

scala> val pairMap = pairs.toMap
pairMap: scala.collection.immutable.Map[Int,Int] = 
      Map(5 -> 10, 1 -> 2, 2 -> 4, 3 -> 6, 4 -> 8)

scala> pairMap.getClass
res0: Class[_ <: scala.collection.immutable.Map[Int,Int]] = 
      class scala.collection.immutable.HashMap$HashTrieMap

Note: casting to be a hashmap doesn't at all change the underlying thing. If you wanted to guarantee building a hashmap (or some specific type), then I'd recommend this:

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

scala> val pairMap = immutable.HashMap(pairs: _*)
pairMap: scala.collection.immutable.HashMap[Int,Int] = 
      Map(5 -> 10, 1 -> 2, 2 -> 4, 3 -> 6, 4 -> 8)

If you're looking for performance improvements you should look into using a mutable.HashMap or java.util.HashMap. Most of scala's collections are out-performed by the native java.util collections.

Upvotes: 4

Related Questions