tags:

views:

439

answers:

4

I would like to convert a Map[Int, Any] to a SortedMap or a TreeMap and haven't been able to find an easy way to do it.

+8  A: 

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.

sblundy
+6  A: 

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
Ben Lings
+12  A: 

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: http://stackoverflow.com/questions/1715681/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]
retronym
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
I had the same problem. The `A` should be `Char`. Similar problem for retrieving `(Int, Int)` as the element type of a Map.
retronym
@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
how about: http://paste.pocoo.org/show/193809/?
IttayD
IttayD: I suspect that solves a slightly different problem, but need to look at it more closely. Thanks!
retronym
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
A: 

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
Alexander Kosenkov