2

I want to sort a scala map by key length. The map looks something like:

val randomMap = Map("short" -> "randomVal1", "muchlonger" -> "randomVal2")

I want to sort randomMap such that when I iterate over it, I will start with the longest key first...so it should iterate over the "muchlonger" element first.

1
  • 2
    A Map (or Associative Array) is generally unordered - that is, the simple ADT does not provide such order guarantees. One could use a List[Tuple2[..]] (or other sequence of key-value pairs, etc) to maintain the ordering after a sort operation. Alternatively, see SortedMap if accessing by key is still important. Commented Sep 6, 2013 at 3:12

2 Answers 2

3

Convert it to a sequence of key/value pairs and apply a sorting criteria. eg.:

randomMap.toSeq.sortBy(_._1.length).reverse

(reverse because it sorts by shortest to longest by default).

Sign up to request clarification or add additional context in comments.

1 Comment

Or just use randomMap.toSeq.sortBy(-_._1.length) and skip the intermediate collection.
1

One option would be to define a custom ordering for a TreeMap. TreeMap is a sorted implementation of Map

import scala.collection.immutable.TreeMap

implicit object LengthOrder extends Ordering[String] { 
    def compare(s1: String, s2: String) = s1.length - s2.length 
}

val randomMap = TreeMap("111" -> "111", "1" -> "1", "11" -> "11")

//randomMap: TreeMap[String,String] = Map(1 -> 1, 11 -> 11, 111 -> 111)

val keys = randomMap.keys
//keys: Iterable[String] = Set(1, 11, 111)

Note that this will affect all TreeMap[String]s where LengthOrder is in scope. In your project you could nest LengthOrder in another object (or put it in its own package) and then only import it inside the specific code blocks that need it.


Edit:

@Bharadwaj made a good point about how this would destroy all but one keys that have the same length. Something like this would fix this issue:

implicit object LengthOrder extends Ordering[String] { 
    def compare(s1: String, s2: String) = s1.length - s2.length match {
      case 0 => s1.compareTo(s2)
      case x => x
    }
}

2 Comments

this will knock off one of the keys from a map which has 2 keys of equal length. dangerous!
Good catch. I've made an edit with a Ordering that fixes this issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.