简体   繁体   English

如何在Scala中实现嵌套地图

[英]how to implement Nested Map in scala

I am trying to implement a nested map in scala in play framework. 我正在尝试在play框架的scala中实现嵌套地图。 what I am trying to achieve is a map which is of type Map[String, Map[Long,Int]] . 我要实现的是Map[String, Map[Long,Int]]类型的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. 发生问题是因为您仅在if中设置了临时timeKey ,而在if外仍需要此值。 This will make your program to always insert the first timeStamp of a given eventType as 0 : 这将使您的程序始终将给定eventType的第一个timeStamp插入为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 : 要解决此问题,只需将代码移出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: 我知道您没有询问它,但是我认为拥有一个更惯用的Scala代码会很好:

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 PS:我将Events重命名为Event

PS2: Notice how the bug you stumbled upon is more difficult to happen when you are programming in a more idiomatic way. PS2:请注意,当您以一种更加惯用的方式进行编程时,您偶然发现的错误是多么难以发生。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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