Johny T Koshy
Johny T Koshy

Reputation: 3922

Odd behavior of mutable.ListMap

I am trying to filter a ListMap with values in a List. But the order is not maintained in output mutable.ListMap. This is a simplified code. As there are constraints and validation checks to be done, I cant do this with filter.

Here is my code,

val inMap = scala.collection.immutable.ListMap((1,5),(2,4),(3,5),(7,6))
val alist= List(1,2,3)
val mutableTempMap = scala.collection.mutable.ListMap.empty[Int, Int]

for (jkey <- alist) {
  inMap.get(jkey) match {
    case Some(y) => mutableTempMap(jkey) = y
    case None    =>
  }
}

mutableTempMap

Output:

scala.collection.mutable.ListMap[Int,Int] = Map(3 -> 5, 1 -> 5, 2 -> 4)

Expected Output

scala.collection.mutable.ListMap[Int,Int] = Map(1 -> 5, 2 -> 4, 3 -> 5)

Upvotes: 0

Views: 115

Answers (3)

Johny T Koshy
Johny T Koshy

Reputation: 3922

The assumption that mutable.ListMap maintains the order is wrong. Its not in the contract. The best option is to use LinkedHashMap.

Also see:

Scala Map implementation keeping entries in insertion order?

Upvotes: 0

Rok Kralj
Rok Kralj

Reputation: 48775

First of all, because of the ListMap being a singly linked list behind the scenes, you gain absolutely no performance with the mutable version, versus the var immutable.

Appart from that, it really has a weird insert pattern, so let's test it out:

val m = collection.mutable.ListMap.empty[Int,Int]
(1 to 10).foreach {i =>
   m(i) = i
   println(m)
}

Produces this output. Notice how after each insert, the tail is reversed, so there is your answer.

Map(1 -> 1)
Map(2 -> 2, 1 -> 1)
Map(3 -> 3, 1 -> 1, 2 -> 2)
Map(4 -> 4, 2 -> 2, 1 -> 1, 3 -> 3)
Map(5 -> 5, 3 -> 3, 1 -> 1, 2 -> 2, 4 -> 4)
Map(6 -> 6, 4 -> 4, 2 -> 2, 1 -> 1, 3 -> 3, 5 -> 5)
Map(7 -> 7, 5 -> 5, 3 -> 3, 1 -> 1, 2 -> 2, 4 -> 4, 6 -> 6)
Map(8 -> 8, 6 -> 6, 4 -> 4, 2 -> 2, 1 -> 1, 3 -> 3, 5 -> 5, 7 -> 7)
Map(9 -> 9, 7 -> 7, 5 -> 5, 3 -> 3, 1 -> 1, 2 -> 2, 4 -> 4, 6 -> 6, 8 -> 8)
Map(10 -> 10, 8 -> 8, 6 -> 6, 4 -> 4, 2 -> 2, 1 -> 1, 3 -> 3, 5 -> 5, 7 -> 7, 9 -> 9)

I would probably vote this being a bug, despite the fact that maps are not ordered.

Upvotes: 1

jwvh
jwvh

Reputation: 51271

Order is maintained if you use an immutable ListMap. Mutability (shudder) can be achieved with a var.

var ilm = collection.immutable.ListMap.empty[Int,Int]
ilm = ilm + (1 -> 5)
ilm = ilm + (2 -> 4)
ilm = ilm + (3 -> 5)
// ilm: immutable.ListMap[Int,Int] = Map(1 -> 5, 2 -> 4, 3 -> 5)

Upvotes: 1

Related Questions