Convert list to a map with key being an index in Scala

1k Views Asked by At

I have a list of strings

val list = List("a", "b", "c", "d", "e")

and I want to have a map with keys as indexes of items in list. So I did the following:

def mapByIndexes(list: List[String]): Map[Int, String] = (1 to list.size).zip(list).toMap

However, the resulting map does not preserve the index order and I'm getting this as a result:

Map(5 -> "e", 1 -> "a", 2 -> "b", 3 -> "c", 4 -> "d") 

How can I modify the code above so I'm getting a map with the following, natural order?

Map(1 -> "a", 2 -> "b", 3 -> "c", 4 -> "d", 5 -> "e") 

Note: I'm aware that I can just sort the resulting map, but can I avoid that step and create a map that already preserves the order?

Edit: Solution with ListMap described at Scala LinkedHashMap.toMap preserves order? works, but I don't like additional parentheses and _* for so simple thing. Isn't there anything else so I can just have a chaining? If not, I will accept @pamu answer.

2

There are 2 best solutions below

7
On BEST ANSWER

I'm aware that I can just sort the resulting map

No, you can't. Sorting a Map doesn't make sense. But there are Map implementations which store keys in natural order, such as TreeMap (IntMap also does, IIRC). Note that it is not the same as preserving insertion order, as ListMap and LinkedHashMap do.

Solution with ListMap described at Scala LinkedHashMap.toMap preserves order? works, but I don't like additional parentheses and _* for so simple thing. Isn't there anything else so I can just have a chaining?

No (at least, I don't think so), but you can easily define it:

implicit class ToListMap[A, B](x: Seq[(A, B)]) {
  def toListMap = ListMap(x: _*)
}

// somewhere where ToListMap is in scope or imported:
val list = List(1 -> 2, 3 -> 4)
list.toListMap

Be aware that ListMap is basically a list (as the name says), so lookups in it are slower than any reasonable map implementation.

Of course, you can do exactly the same with TreeMap.

1
On

Use ListMap. After zipping instead of doing toMap, Just construct the ListMap which preserves the order of elements. You can build a ListMap using its companion object. It accepts var args of tuples.

def mapByIndexes(list: List[String]): ListMap[Int, String] = ListMap((1 to list.size).zip(list): _*)

Scala REPL

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

scala> def mapByIndexes(list: List[String]): ListMap[Int, String] = ListMap((1 to list.size).zip(list): _*)
mapByIndexes: (list: List[String])scala.collection.immutable.ListMap[Int,String]

scala> mapByIndexes(list)
res10: scala.collection.immutable.ListMap[Int,String] = Map(1 -> a, 2 -> b, 3 -> c, 4 -> d, 5 -> e)