I would like to convert a Map[Int, Any]
to a SortedMap
or a TreeMap
. Is there an easy way to do it?

- 30,738
- 21
- 105
- 131

- 909
- 3
- 11
- 17
6 Answers
An alternative to using :_*
as described by sblundy is to append the existing map to an empty SortedMap
import scala.collection.immutable.SortedMap
val m = Map(1 -> ("one":Any))
val sorted = SortedMap[Int, Any]() ++ m

- 28,823
- 13
- 72
- 81
-
4How does this compare to the other options in terms of performance? – TimY Jun 20 '15 at 11:19
-
3i would write that as `val sorted = SortedMap.empty[Int,Any] ++ m` since as written it reads like it is constructing a wasted empty map although hopefully the compiler is smart enough not to. – simbo1905 Jul 06 '15 at 20:28
Assuming you're using immutable maps
val m = Map(1 -> "one")
val t = scala.collection.immutable.TreeMap(m.toArray:_*)
The TreeMap
companion object's apply method takes repeated map entry parameters (which are instances of Tuple2[_, _]
of the appropriate parameter types). toArray
produces an Array[Tuple2[Int, String]]
(in this particular case). The : _*
tells the compiler that the array's contents are to be treated as repeated parameters.

- 26,420
- 4
- 61
- 81

- 60,628
- 22
- 121
- 123
-
4This is a correct answer. But it shows an ugly side of the scala collections: it is too awkward. – WestCoastProjects Aug 30 '14 at 23:59
-
1Is this going to push the entire contents of m onto the stack as method arguments? Or is Scala/Java smarter than that? – Rag Jun 20 '15 at 02:49
-
1This solution is inefficient, as it first copies the entire copies of the `Map` to an array, and then copies the array into a `TreeMap.Builder`. – reggert Mar 08 '17 at 16:19
Here's a general way to convert between various Scala collections.
import collection.generic.CanBuildFrom
import collection.immutable.TreeMap
object test {
class TraversableW[A](t: Traversable[A]) {
def as[CC[X] <: Traversable[X]](implicit cbf: CanBuildFrom[Nothing, A, CC[A]]): CC[A] = t.map(identity)(collection.breakOut)
def to[Result](implicit cbf: CanBuildFrom[Nothing, A, Result]): Result = t.map(identity)(collection.breakOut)
}
implicit def ToTraverseableW[A](t: Traversable[A]): TraversableW[A] = new TraversableW[A](t)
List(1, 2, 3).as[Vector]
List(1, 2, 3).to[Vector[Int]]
List((1, 1), (2, 4), (3, 4)).to[Map[Int, Int]]
List((1, 1), (2, 4), (3, 4)).to[TreeMap[Int, Int]]
val tm: TreeMap[Int, Int] = List((1, 1), (2, 4), (3, 4)).to
("foo": Seq[Char]).as[Vector]
}
test
See also this question describing collection.breakOut
: Scala 2.8 breakOut
CHALLENGE
Is it possible to adjust the implicits such that this works? Or would this only be possible if as
were added to Traversable
?
"foo".as[Vector]
-
You can make the implicit receive a view bound instead of a Traversable, but I can't think of a way to retrieve "A" from that. After all, `String` doesn't have an "A". – Daniel C. Sobral Jun 20 '10 at 01:15
-
I had the same problem. The `A` should be `Char`. Similar problem for retrieving `(Int, Int)` as the element type of a Map. – retronym Jun 20 '10 at 07:28
-
@retronym - really appreciate your post on my simple "scala newbie" question. Sent me on a good dive with the link you posted on collection.breakout. – Vonn Jun 21 '10 at 18:51
-
IttayD: I suspect that solves a slightly different problem, but need to look at it more closely. Thanks! – retronym Jun 22 '10 at 11:28
-
I think this conversation (http://www.scala-lang.org/node/5677) and bug (https://lampsvn.epfl.ch/trac/scala/ticket/3201) are relevant. I ran into them coming at this problem from a slightly different angle: http://gist.github.com/445874 – retronym Jun 22 '10 at 11:30
-
1Assuming the contest is still open, here is how I would do it: http://ideone.com/pVZVW – missingfaktor Jul 23 '11 at 19:31
-
As-of at least Scala 2.12, the collections have a predefined `to` method that does what this `as` does, and also creates a naming conflict that will give a compiler error _{target type} takes no type parameters, expected: one_. The fix is to eliminate the `as` method given above and rename `to` to `as` so the names don't collide. – WeaponsGrade Jun 20 '19 at 14:30
Starting Scala 2.13
, via factory builders applied with .to(factory)
:
Map(1 -> "a", 2 -> "b").to(collection.immutable.SortedMap)
// collection.immutable.SortedMap[Int,String] = TreeMap(1 -> "a", 2 -> "b")
Map(1 -> "a", 2 -> "b").to(collection.immutable.TreeMap)
// collection.immutable.TreeMap[Int,String] = TreeMap(1 -> "a", 2 -> "b")

- 54,987
- 21
- 291
- 190
Here's a way you can do it with a Scala implicit class:
implicit class ToSortedMap[A,B](tuples: TraversableOnce[(A, B)])
(implicit ordering: Ordering[A]) {
def toSortedMap =
SortedMap(tuples.toSeq: _*)
}
Since Map[A,B] has an implicit path to a TraversableOnce[Tuple2[A, B]], the following works:
scala> Map("b" -> 3, "c" -> 3, "a" -> 5).toSortedMap
res6: scala.collection.immutable.SortedMap[String,Int] = Map(a -> 5, b -> 3, c -> 3)
It will even work on a list of Tuple2s, similar to toMap:
scala> List(("c", 1), ("b", 3),("a", 6)).toSortedMap
res7: scala.collection.immutable.SortedMap[String,Int] = Map(a -> 6, b -> 3, c -> 1)

- 2,561
- 20
- 23
Since internal data structures in implementations are completely different, you'll have to add elements one-by-one anyway. So, do it explicitly:
val m = Map(1 -> "one")
var t = scala.collection.immutable.TreeMap[Int,String]()
t ++= m

- 1,597
- 1
- 10
- 21