Home > Enterprise >  How to sort 'Map' values in Scala against multiple factors?
How to sort 'Map' values in Scala against multiple factors?

Time:09-17

I have a Map (datatype) with the following data structure:

var timePassedCamerasetB = mutable.Map.empty[String, Time];

It contains a String and a 'Time' object. The 'Time' object is made up from my own class. Below you can see what it consists of:

case class Time(daysSinceEpoch: Int, hours: Int, minutes: Int, seconds: Double)

I have saved all my data into this 'Map' variable. But there is one problem: I want to sort the values in this 'Map' variable based on multiple things, but I can't find any way to make it work.

For example. I have stored the following data within this map:

PP-33-XX -> Time(18492,3,7,0.0)
BA-12-PW -> Time(18492,9,0,40.0)
MM-11-OW -> Time(18492,3,7,16.0)
NX-66-PP -> Time(18492,3,6,30.0)
LA-53-NY -> Time(18492,9,0,56.0)

I want to sort the values in order (earliest time to latest time). This includes comparing multiple factors. First compare each daysSinceEpoch, then hours, minutes and seconds.

I want to transform the map into the following down below:

NX-66-PP -> Time(18492,3,6,30.0)
PP-33-XX -> Time(18492,3,7,0.0)
MM-11-OW -> Time(18492,3,7,16.0)
BA-12-PW -> Time(18492,9,0,40.0)
LA-53-NY -> Time(18492,9,0,56.0)

Does anyone know of an efficient way to do this? Unfortunately I can't..

CodePudding user response:

As Luis commented, Maps, specifically mutable.Map aren't designed to hold ordered values. If you could go with a List it can be easily sorted like this:

timePassedCamerasetB
    .toList
    .sortBy {
      case (_, time) => (time.daysSinceEpoch, time.hours, time.minutes, time.seconds)
    }

This expression has to be assigned to new value

CodePudding user response:

It sounds like a ListMap is what you want.

From the ScalaDocs page: "Entries are stored internally in reversed insertion order, which means the newest key is at the head of the list."

So to transit from the current Map to a ListMap:

import scala.collection.immutable.ListMap

val newMap: ListMap[String,Time] = 
  oldMap.toList.sortBy{
    case (_, Time(d,h,m,s)) => (d,h,m,s)
  }.foldLeft(ListMap[String,Time]())(_ _)

testing:

newMap.head //res0: (NX-66-PP,Time(18492,3,6,30.0))
newMap.last //res1: (LA-53-NY,Time(18492,9,0,56.0))
newMap("MM-11-OW")    //res2: Time(18492,3,7,16.0)
  • Related