Immutable Scala Map implementation that preserves insertion order

ScalaDictionaryCollectionsImmutability

Scala Problem Overview


LinkedHashMap is used to preserve insertion order in the map, but this only works for mutable maps. Which is the immutable Map implementation that preserves insertion order?

Scala Solutions


Solution 1 - Scala

ListMap implements an immutable map using a list-based data structure, and thus preserves insertion order.

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

scala> ListMap(1 -> 2) + (3 -> 4)
res31: scala.collection.immutable.ListMap[Int,Int] = Map(1 -> 2, 3 -> 4)

scala> res31 + (6 -> 9)
res32: scala.collection.immutable.ListMap[Int,Int] = Map(1 -> 2, 3 -> 4, 6 -> 9)

The following extension method - Seq#toListMap can be quite useful when working with ListMaps.

scala> import scalaz._, Scalaz._, Liskov._
import scalaz._
import Scalaz._
import Liskov._

scala> :paste
// Entering paste mode (ctrl-D to finish)

implicit def seqW[A](xs: Seq[A]) = new SeqW(xs)
class SeqW[A](xs: Seq[A]) {
  def toListMap[B, C](implicit ev: A <~< (B, C)): ListMap[B, C] = {
    ListMap(co[Seq, A, (B, C)](ev)(xs) : _*)  
  }
}


// Exiting paste mode, now interpreting.

seqW: [A](xs: Seq[A])SeqW[A]
defined class SeqW

scala> Seq((2, 4), (11, 89)).toListMap
res33: scala.collection.immutable.ListMap[Int,Int] = Map(2 -> 4, 11 -> 89)

Solution 2 - Scala

While ListMap will preserve insertion order, it is not very efficient - e.g. lookup time is linear. I suggest you create a new collection class which wraps both the immutable.HashMap and the immutable.TreeMap. The immutable map should be parametrized as immutable.HashMap[Key, (Value, Long)], where the Long in the tuple gives you the pointer to the corresponding entry in the TreeMap[Long, Key]. You then keep an entry counter on the side. This tree map will sort the entries according to the insertion order.

You implement insertion and lookup in the straightforward way - increment the counter, insert into the hash map and insert to the the counter-key pair into the treemap. You use the hash map for the lookup.

You implement iteration by using the tree map.

To implement remove, you have to remove the key-value pair from the hash map and use the index from the tuple to remove the corresponding entry from the tree map.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatroskaView Question on Stackoverflow
Solution 1 - ScalamissingfaktorView Answer on Stackoverflow
Solution 2 - Scalaaxel22View Answer on Stackoverflow