如何在Scala中处理Map上的复杂操作

时间:2015-09-08 05:44:25

标签: java scala dictionary

我是Scala编程的新手,但在Java方面有多年的经验。

Java中有一个简单的问题让我在Scala中挣扎。

我有一些来自数据库的记录

+----+--------+--------------+------+
| id | level  | subLevel     | name |
+----+--------+--------------+------+
|  3 | level1 | subLevel1    | three|
|  4 | level2 | subLevel1    | four |
|  5 | level2 | subLevel1    | five |
+----+--------+--------------+------+

需要像这样总结到Map

{
    "level1": {
        "subLevel1": [
            {
                "id": "3",
                "name": "three"
            }
        ]
    },
    "level2": {
        "subLevel1": [
            {
                "id": "4",
                "name": "four"
            },
            {
                "id": "5",
                "name": "five"
            }
        ]
    }
}

如果是在Java中,也许我可以这样解决:

public JSONObject centerMap() {
    List<Center> centerList = centerService.getAllCenter();

    Map<String, Map<String, List<Map<String, String>>>> centerMap = new HashMap<String, Map<String, List<Map<String, String>>>>();
    for (Center center : centerList) {
        Map<String, List<Map<String, String>>> subLevelList = centerMap.get(center.getLevel());
        if (subLevelList == null)
            subLevelList = new HashMap<String, List<Map<String, String>>>();

        List<Map<String, String>> names = subLevelList.get(center.getSubLevel());
        if (names == null)
            names = new ArrayList<Map<String, String>>();

        final Center c = center;
        names.add(new HashMap<String, String>(){{
            put("name", c.getName());
            put("id", String.valueOf(c.getId()));
        }});
        subLevelList.put(center.getSubLevel(), names);
        centerMap.put(center.getLevel(), subLevelList);
    }

    return JSONObject.fromObject(centerMap);
}

我真的不知道在Scala中做到这一点的最佳方法 但几乎可以肯定不是scala.collection.mutable.Map

2 个答案:

答案 0 :(得分:1)

考虑一个案例类,例如

case class Entry(id: Int, level: String, subLevel: String, name: String)

和一系列条目,

val entries = Array(
  Entry(3, "level1", "subLevel1", "three"),
  Entry(4, "level2", "subLevel1", "four"),
  Entry(5, "level2", "subLevel1", "five"))

然后考虑将此类值分组为levelsubLevel,如下所示,

entries.groupBy { case Entry(id,level,subLevel,name) => (level,subLevel)}

因此

Map((level1,subLevel1) -> Array(Entry(3,level1,subLevel1,three)), 
    (level2,subLevel1) -> Array(Entry(4,level2,subLevel1,four), 
                                Entry(5,level2,subLevel1,five)))

答案 1 :(得分:1)

以榆树的答案为基础。

当制作更大且更永久的地图时,我倾向于通过在同一地图中添加几个不同的groupBy来扩展elm提出的模式。

case class LevelKey(level:String)
case class NameKey(name:String)
case class SublevelKey(level:String,subLevel:String)

val finalMap={
   val bySublevel=xs.groupBy(v=>SublevelKey(v.level,v.subLevel))
   val bylevel=xs.groupBy(v=>LevelKey(v.level))
   val byName=xs.groupBy(v=>NameKey(v.name))
   bySublevel++byLevel++byName
}

这样,您可以从同一个地图按级别,子级别或名称访问地图。使用案例类作为键使访问代码非常易读。

finalMap.get(LevelKey("level1"))
finalMap.get(NameKey("five"))
finalMap.get(SubLevelKey("level1", "subLevel1"))

案例类的hashcode()和equals()方法非常快。根据我的经验,与在地图中使用地图的模式相比,此模式可以导致速度增加。