user2780187
user2780187

Reputation: 727

Scala - Sort a Map based on Tuple Values

I am attempting to sort a Map based on Value Tuples

val data = Map("ip-11-254-25-225:9000"  -> (1, 1413669308124L), 
               "ip-11-232-145-172:9000" -> (0, 1413669141265L), 
               "ip-11-232-132-31:9000"  -> (0, 1413669128111L), 
               "ip-11-253-67-184:9000"  -> (0, 1413669134073L), 
               "ip-11-232-142-77:9000"  -> (0, 1413669139043L))

The criteria of sort should be based on both the values in the tuple

I tried

SortedMap[String, (Long,Long)]() ++ data

but with no success.

Can someone please suggest a better way to sort first on tuple._1 and then on tuple._2

Upvotes: 1

Views: 1639

Answers (3)

Nader Ghanbari
Nader Ghanbari

Reputation: 4310

Sorting Tuples

First note that if you sort a collection of tuples you will get the same result as you expect, i.e. first items will be compared first and then second items.

For example (a1, b1) > (a2, b2) if and only if (a1 > a2) || ((a1 == a2) && (b1 > b2)).

So for getting the expected result in terms of sorting tuples you don't need to do anything.

Then it remains to how to sort a map based on values and how to preserve the order after sorting.

Sort map on values

You can use the sortBy method of List and then use an ordered data structure to preserve the ordering, like this:

new scala.collection.immutable.ListMap() ++ data.toList.sortBy(_._2)

If you run this in Scala REPL you will get the follwoing result:

scala> new scala.collection.immutable.ListMap() ++ data.toList.sortBy(_._2)
res3: scala.collection.immutable.ListMap[String,(Int, Long)] = Map(ip-11-232-132-31:9000 -> (0,1413669128111), ip-11-253-67-184:9000 -> (0,1413669134073), ip-11-232-142-77:9000 -> (0,1413669139043), ip-11-232-145-172:9000 -> (0,1413669141265), ip-11-254-25-225:9000 -> (1,1413669308124))

If you simply want to sort them and traverse the result (i.e. if you don't need a map as result) you don't even need to use ListMap.

Upvotes: 1

elm
elm

Reputation: 20435

In general you can select which element in the tuple has priority in the sorting; consider this

data.toSeq.sortBy {case (k,(a,b)) => (k,a,b) }

In the case pattern we extract each element of the (nested) tuples. In the expression above we sort by key, then by first element in value tuple and then second. On the other hand, this

data.toSeq.sortBy {case (k,(a,b)) => (k,b) }

will sort by key and last element in value tuple, and this

data.toSeq.sortBy {case (k,(a,b)) => (a,b) }

by the values of the map; this one

data.toSeq.sortBy {case (k,(a,b)) => (b) }

will sort by the last element in the values tuple.

Update As helpfully pointed out by @Paul a Map preserves no ordering, hence the result remains here as a sequence.

Upvotes: 3

dhg
dhg

Reputation: 52701

Is this what you're looking for?

data.toVector.sortBy(_._2)

This will sort the entries by the values (the tuples), where the order depends on both tuple arguments. The default sort behavior for a tuple is to sort on _1 and then _2:

Vector((2,1), (1,2), (1,3), (1,1)).sorted
// Vector((1,1), (1,2), (1,3), (2,1))

Upvotes: 1

Related Questions