49

I have a Seq containing objects of a class that looks like this:

class A (val key: Int, ...)

Now I want to convert this Seq to a Map, using the key value of each object as the key, and the object itself as the value. So:

val seq: Seq[A] = ...
val map: Map[Int, A] = ... // How to convert seq to map?

How can I does this efficiently and in an elegant way in Scala 2.8?

Eugene Yokota
  • 94,654
  • 45
  • 215
  • 319
Jesper
  • 202,709
  • 46
  • 318
  • 350
  • 1
    Out of curiosity does anyone happen to know why this isn't included in the Scala collections library? – tksfz Feb 19 '15 at 18:59

4 Answers4

90

Since 2.8 Scala has had .toMap, so:

val map = seq.map(a => a.key -> a).toMap

or if you're gung ho about avoiding constructing an intermediate sequence of tuples, then in Scala 2.8 through 2.12:

val map: Map[Int, A] = seq.map(a => a.key -> a)(collection.breakOut)

or in Scala 2.13 and 3 (which don't have breakOut, but do have a reliable .view):

val map = seq.view.map(a => a.key -> a).toMap
Seth Tisue
  • 29,985
  • 11
  • 82
  • 149
  • Thanks. I've seen the `breakOut` thing before but I don't yet know what it is. Time to learn something new again. – Jesper May 28 '10 at 05:10
  • 3
    Found a good explanation of `breakOut` here: http://stackoverflow.com/questions/1715681/scala-2-8-breakout/1716558#1716558 – Jesper Jun 01 '10 at 11:49
  • Why is it that val map = Seq(1,2,3).map(a => a -> a)(collection.breakOut) is actually of type Vector? map: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((1,1), (2,2), (3,3)) – simou Feb 28 '14 at 22:43
  • 1
    I'm not sure offhand. Maybe ask it as a new question? Also see http://stackoverflow.com/a/1716558/86485 – Seth Tisue Mar 01 '14 at 03:45
  • The return type of the mapping with breakOut is a Vector because the default implementation of IndexedSeq is a Vector, as per the docs: https://www.scala-lang.org/api/2.12.0/scala/collection/immutable/IndexedSeq$.html – Joe C. Dec 17 '18 at 17:00
  • But how does IndexedSeq come into it in the first place? – Seth Tisue Dec 21 '18 at 12:07
46

Map over your Seq and produce a sequence of tuples. Then use those tuples to create a Map. Works in all versions of Scala.

val map = Map(seq map { a => a.key -> a }: _*)
Daniel Spiewak
  • 54,515
  • 14
  • 108
  • 120
  • 4
    Using `breakOut` as Seth Tisue shows in another answer can make it more efficient by avoiding creating a temporary sequence of tuples. – Jesper Jun 01 '10 at 11:54
8

One more 2.8 variation, for good measure, also efficient:

scala> case class A(key: Int, x: Int)
defined class A

scala> val l = List(A(1, 2), A(1, 3), A(2, 1))
l: List[A] = List(A(1,2), A(1,3), A(2,1))

scala> val m: Map[Int, A] = (l, l).zipped.map(_.key -> _)(collection.breakOut)
m: Map[Int,A] = Map((1,A(1,3)), (2,A(2,1)))

Note that if you have duplicate keys, you'll discard some of them during Map creation! You could use groupBy to create a map where each value is a sequence:

scala> l.groupBy(_.key)
res1: scala.collection.Map[Int,List[A]] = Map((1,List(A(1,2), A(1,3))), (2,List(A(2,1))))
retronym
  • 54,768
  • 12
  • 155
  • 168
2

As scala knows to convert a Tuple of two to a map, you would first want to convert your seq to a tuple and then to map so (doesn't matter if it's int, in our case string, string):

The general algorithm is this:

  1. For each item in Seq
  2. Item --> Tuple(key, value)
  3. For each tuple(key, value)
  4. Aggregate to Map(key,value)

Or to sum up:

Step 1: Seq --> Tuple of two

Step 2: Tuple of two --> Map

Example:

case class MyData(key: String, value: String) // One item in seq to be converted to a map entry.

// Our sequence, simply a seq of MyData
val myDataSeq = Seq(MyData("key1", "value1"), MyData("key2", "value2"), MyData("key3", "value3")) // List((key1,value1), (key2,value2), (key3,value3))

// Step 1: Convert seq to tuple
val myDataSeqAsTuple = myDataSeq.map(myData => (myData.key, myData.value)) // List((key1,value1), (key2,value2), (key3,value3))

// Step 2: Convert tuple of two to map.
val myDataFromTupleToMap = myDataSeqAsTuple.toMap // Map(key1 -> value1, key2 -> value2, key3 -> value3)
Tomer Ben David
  • 8,286
  • 1
  • 43
  • 24