简体   繁体   中英

how to implement Nested Map in scala

I am trying to implement a nested map in scala in play framework. what I am trying to achieve is a map which is of type Map[String, Map[Long,Int]] . I am not able to assign the value of the parent map which is itself a map. The application is compiling properly but the value is not getting updated. Can you please suggest what I am doing wrong and how to assign a map value to another map?

import java.util.concurrent.ConcurrentHashMap
import scala.collection._
import scala.collection.convert.decorateAsScala._
import scala.collection.JavaConversions.mapAsScalaMap

case class Events(eventType: String, timeStamp: Long)

object Events {

  var eventMap = new ConcurrentHashMap[String, ConcurrentHashMap[Long,Int]]()

  def save(events: Events) = {
    var eventsKey: String = ""
    var count: Int = 1
    var timeKey: Long = 0L
    var newEntry: Boolean = false
    eventsKey = events.eventType
    var countMap = new ConcurrentHashMap[Long,Int]()
    countMap.clear()

    if (eventMap.containsKey(eventsKey)) {
      countMap = eventMap.get(eventsKey) // this is not working
      timeKey = events.timeStamp
      if (countMap.containsKey(timeKey)) { 
        count = countMap(timeKey) + 1
        countMap.put(timeKey, count)
        eventMap.put(eventsKey, countMap)
      } // End of counter check
      else {
        newEntry = true
      }
    } // End of if event key check
    else {
      newEntry = true
    } // End of else event key check

    if (newEntry) {
      countMap.putIfAbsent(timeKey, 1)
      eventMap.putIfAbsent(eventsKey, countMap)
    }
  }
}

The problem is happening because you are only setting temporary timeKey inside the if, and you still need this value outside of the if. This will make your program to always insert the first timeStamp of a given eventType as 0 :

Events.save(Events("aa", 222))     // {aa={0=1}}

Events.save(Events("aa", 333))     // {aa={0=1, 333=1}}

Events.save(Events("aa", 333))     // {aa={0=1, 333=2}}

Events.save(Events("bb", 444))     // {aa={0=1, 333=2}, bb={0=1}}

To fix it, just move the code out of the if :

...     
var newEntry: Boolean = false
eventsKey = events.eventType
timeKey = events.timeStamp // <--- This fixes it
var countMap = new ConcurrentHashMap[Long,Int]()
countMap.clear()

if (eventMap.containsKey(eventsKey)) {
  countMap = eventMap.get(eventsKey) //this is not working

  if (countMap.containsKey(timeKey)) {
    count = countMap(timeKey) + 1
...

Now when you run, you get:

Events.save(Events("aa", 222))     // {aa={222=1}}

Events.save(Events("aa", 333))     // {aa={333=1, 222=1}}

Events.save(Events("aa", 333))     // {aa={333=2, 222=1}}

Events.save(Events("bb", 444))     // {aa={333=2, 222=1}, bb={444=1}}

Extra

I know you didn't asked about it, but I thought it would be nice to have a more idiomatic scala code:

case class Event(eventType: String, timeStamp: Long)

object Event {
  val eventMap = new ConcurrentHashMap[String, ConcurrentHashMap[Long,Int]]()

  def save(event: Event) = {
    val Event(eventKey, timeKey) = event

    val countMap = eventMap.getOrElse(eventKey, new ConcurrentHashMap[Long,Int]())

    val count = countMap.getOrElse(timeKey, 0) + 1

    countMap.put(timeKey, count)
    eventMap.put(eventKey, countMap)
  }
}

PS: I renamed Events to Event

PS2: Notice how the bug you stumbled upon is more difficult to happen when you are programming in a more idiomatic way. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM