030
030

Reputation: 11679

How to order the keys that reside in a map in a certain order using Scala?

Follow up to this question.

How to reorder

List(Map(d -> 4, a -> 12, c -> 30, b -> 2), Map(d -> 80, a -> 22, c -> 6666, b -> 442))

to

List(Map(d -> 4, b -> 2, a -> 12, c -> 30), Map(d -> 80, b -> 442, a -> 22, c -> 6666))

using Scala?

Upvotes: 0

Views: 825

Answers (2)

Zernike
Zernike

Reputation: 1766

SortedMap.apply take implicit Ordering that define order. For example:

implicit val stringReverse = Ordering.String.reverse
val xs = Map("a" -> 3, "b" -> 5)
SortedMap(xs.toList:_*) // Map(b -> 5, a -> 3)

How to define own Ordering

Upvotes: 0

Cyrille Corpet
Cyrille Corpet

Reputation: 5315

A Map is usually an unordered collection. To be more precise, a Map is a Set of keys with values attached to them. Since Sets only have distinct elements, and aren't ordered, so are Maps.

SortedMap[String, Int]

However, there is an implementation of Map with sorted keys, and that's SortedMap. It uses an implicit Ordering[Key] to keep key-value pairs ordered by their key (note that it keeps unicity of keys, so that you cannot have two values for a given key).

For instance

SortedMap(-1 -> "neg", 1 -> "pos") + (0 -> "zero") ==
  SortedMap(-1 -> "neg", 0 -> "zero", 1 -> "pos")

However, in your case, it might be difficult to keep an implicit Ordering[String] different from the usual one (which is lexicographical order).

Seq[(String, Int)]

You might want to convert your Map[String, Int] to a Seq[(String, Int)]. That way, you can play with the order of your values, but you'll loose the fast lookup for a given key.

If you want to do this, you can specify your order first by using a list of keys in order, and then mapping on it using the original map.

val original: Map[String, Int] = Map("d" -> 4, "a" -> 12, "c" -> 30, "b" -> 2)
orderedMap: List[(String, Int)] = for {
    key <- List("d", "b", "a", "c")
    value <- original.get(key)
  } yield key -> value

Note that I used original.get(key) to avoid the case where one of your keys is not actually defined in the original map.

Now, to get a value for a given key, using this List[(String, Int)] type, you have to do

def getKey(key: String): Option[Int] = orderedMap.
  find(_._1 == key).  //find the first pair where the first element is the desired key
  map(_._2)  // keep only the value if it exists.

Upvotes: 2

Related Questions