2

Example:

val occ = List(('l', 2), ('n', 1), ('r', 1), ('u', 2), ('x', 1))
occ.toMap
// Map(x -> 1, n -> 1, u -> 2, l -> 2, r -> 1)

The elements are no longer sorted in alphabetical order. Why does this happen?

Jeffrey Chung
  • 19,319
  • 8
  • 34
  • 54
Emma Liu
  • 33
  • 5
  • @CannedMoose if we use sorted map then only it will sort the map by key it's not the case always. – Raman Mishra Jun 20 '18 at 07:05
  • 1
    Possible duplicate of [Scala Map implementation keeping entries in insertion order?](https://stackoverflow.com/questions/3835743/scala-map-implementation-keeping-entries-in-insertion-order) – Raman Mishra Jun 20 '18 at 07:06
  • The question asked about a 'toMap' method in List, I see it is different with ListMap. And I do not find an answer in the question recommended. – Emma Liu Jun 22 '18 at 11:32

3 Answers3

5

Maps are not sorted and the keys may be in any order depending on implementation.

However a ListMap preserves the order of addition. You can build a ListMap using the normal Map operations, or you can create one from a List like this:

ListMap(occ:_*)
Tim
  • 26,753
  • 2
  • 16
  • 29
  • I know there are ways to preserve the order. I am just curious why converting to map do not preserve the order. What is reason/concern in implementation the "toMap" method. – Emma Liu Jun 22 '18 at 11:24
  • 1
    @EmmaLiu `toMap` just converts the `List` to a `Map`. It is the implementation of `Map` that matters. This is typically done with a table indexed by a hash of the key value (hence `HashMap`). The order of the keys will be the order of the hashed values, not the order of the keys themselves. – Tim Jun 22 '18 at 20:44
  • @EmmaLiu: A map *has no order*. It doesn't preserve the order *because there is no order to preserve*. – Jörg W Mittag Jun 24 '18 at 10:46
  • @Tim Your explanation answers my question. Thanks a lot. – Emma Liu Jun 25 '18 at 02:51
2

Edit: there's a LinkedMap coming in 2.13 with different trade-offs.

Edit: the question is really that you might expect list.toMap to produce a ListMap. Why doesn't it?

The doc says "inserting or removing entries, are also O(n), which makes this collection suitable only for a small number of elements."

So that's another sensitivity to size. Often you create a collection as pairs resulting from other operations and you just want to dump them into a map, often a large one.

--

There is sensitivity to size due to specialization. There are custom maps for the smallest sizes. This isn't guaranteed, but is confusing if you notice the pattern.

scala $ ~/scala-2.12.6/bin/scala -Dscala.repl.info
Welcome to Scala 2.12.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144).
Type in expressions for evaluation. Or try :help.
[info] started at Wed Jun 20 00:17:33 PDT 2018

scala 2.12.6> val m = List(1->10,2->20,3->30,4->40).toMap
m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 10, 2 -> 20, 3 -> 30, 4 -> 40)

scala 2.12.6> val m = List(1->10,2->20,3->30,4->40,5->50).toMap
m: scala.collection.immutable.Map[Int,Int] = Map(5 -> 50, 1 -> 10, 2 -> 20, 3 -> 30, 4 -> 40)

scala 2.12.6> :quit
scala $ ~/scala-2.13.0-M4/bin/scala -Dscala.repl.info
[info] started at Wed Jun 20 00:18:41 PDT 2018
Welcome to Scala 2.13.0-M4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144).
Type in expressions for evaluation. Or try :help.

scala 2.13.0-M4> val m = List(1->10,2->20,3->30,4->40).toMap
m: scala.collection.immutable.Map[Int,Int] = ChampHashMap(1 -> 10, 2 -> 20, 3 -> 30, 4 -> 40)

scala 2.13.0-M4> val m = List(1->10,2->20,3->30,4->40,5->50).toMap
m: scala.collection.immutable.Map[Int,Int] = ChampHashMap(5 -> 50, 1 -> 10, 2 -> 20, 3 -> 30, 4 -> 40)
som-snytt
  • 39,429
  • 2
  • 47
  • 129
  • Yes, I do noticed this. For very small maps, the conversion keeps the element in order. But for slightly larger map, the order is not longer preserved, but determined. – Emma Liu Jun 22 '18 at 11:25
1

You can use ListMap instead of Map, it keeps items in the order they were inserted. To convert List to ListMap:

val occ = List(('l', 2), ('n', 1), ('r', 1), ('u', 2), ('x', 1))
ListMap(occ: _*)

In case you don't know what _* means - repeated parameters

Svitovyda
  • 26
  • 1
  • 6