如何在Scala中执行嵌套groupBy

时间:2016-02-03 19:23:21

标签: json scala collections group-by nested

我有一个像这样的案例对象列表:

AppInfo(client = "client1", project = "project1", version = "version1")
AppInfo(client = "client1", project = "project1", version = "version2")
AppInfo(client = "client2", project = "project3", version = "version1")
AppInfo(client = "client2", project = "project4", version = "version1")

需要制作这样的嵌套结构:

Map(
  "clients" -> List(
    Map(
      "name" -> "client1",
      "projects" -> List(
        Map(
          "name" -> "project1",
          "versions" -> List(
            "version1",
            "version2"
          )
        )
      )
    ),
    Map(
      "name" -> "client2",
      "projects" -> List(
        Map(
          "name" -> "project3",
          "versions" -> List(
            "version1"
          )
        ),
        Map(
          "name" -> "project4",
          "versions" -> List(
            "version1"
          )
        )
      )
    )
  )
)

看起来很糟糕,但它会序列化为这个非常简单的JSON:

{
  "clients": [
    {
      "name": "client1",
      "projects": [
        {
          "name": "project1",
          "versions": [
            "version1",
            "version2"
          ]
        }
      ]
    },
    {
      "name": "client2",
      "projects": [
        {
          "name": "project3",
          "versions": [
            "version1"
          ]
        },
        {
          "name": "project4",
          "versions": [
            "version1"
          ]
        }
      ]
    }
  ]
}

有没有合理的方法呢?现在我在列表中的groupBys中的地图中有地图。

修改

Clojure的Specter库可能会有所帮助。

3 个答案:

答案 0 :(得分:2)

怎么样:

for {
    (clientName, clientInfos) <- infoList.groupBy(_.client)
} yield {
    val clientProjects = clientInfos.groupBy(_.project)
    val projectSection = clientProjects.map { case(name, infos) => Map("name" -> name, "versions" -> infos.map(_.version)) }

    Map("name" -> clientName, "projects" -> projectSection)
}

它不会减少mapgroupBy次调用的次数,但这是我能够组织代码的最便捷方式。

答案 1 :(得分:0)

给定一个名为AppInfo的{​​{1}}案例对象列表,执行appInfos

byClient(appInfos)

重复,但完成工作。

答案 2 :(得分:0)

案例类将为您提供比地图更好的类型安全性,但更丑陋:

给出名为AppInfo的{​​{1}}案例对象列表appInfos

byClient2(appInfos)