2016-02-03 37 views
3

我有格的對象列表如下:如何做一個嵌套GROUPBY在斯卡拉

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" 
      ] 
     } 
     ] 
    } 
    ] 
} 

是否有任何合理的方法來做到這一點?現在我在Maps中的地圖中有groupBys內的地圖。

編輯

有點像Specter庫Clojure的可能有助於在這裏。

回答

1

如何:

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,但是th這是我能夠組織代碼的最方便的方式。

+0

謝謝,我會試試看!我喜歡你如何使用模式匹配來避免像'tuple._1'和'tuple._2'這樣的東西。 –

0

鑑於AppInfo箱子對象的列表稱爲appInfos,做byClient(appInfos)

def byVersion(appInfos: List[AppInfo]) = appInfos 
              .map(_.version) 

def byProject(appInfos: List[AppInfo]) = appInfos 
              .groupBy(_.project) 
              .map(tuple => Map("name" -> tuple._1, "versions" -> byVersion(tuple._2))) 

def byClient(appInfos: List[AppInfo]) = appInfos 
              .groupBy(_.client) 
              .map(tuple => Map("name" -> tuple._1, "projects" -> byProject(tuple._2))) 

這是重複的,但能夠完成任務。

0

案例課程會給你更好的類型安全比地圖,但更醜:

鑑於AppInfo箱子對象的列表稱爲appInfosbyClient2(appInfos)

case class ProjectApps(name: String, versions: List[String]) 

object ProjectApps{ 
    def apply(tuple: (String, List[AppInfo])): ProjectApps = 
       ProjectApps(name=tuple._1, versions=tuple._2.map(_.version)) 
} 


case class ClientApps(name: String, projects: List[ProjectApps]) 

object ClientApps { 
    def apply(tuple: (String, List[AppInfo])): ClientApps = { 
    val name = tuple._1 
    val projects = tuple._2.groupBy(_.project).map(ProjectApps.apply).toList 
    ClientApps(name, projects) 
    } 
} 


def byClient2(appInfos: List[AppInfo]): List[ClientApps] = 
        appInfos.groupBy(_.client).map(ClientApps.apply).toList 
+0

標記爲答案,因爲類型安全性很好,使用case類可以更容易地生成諸如JSON模式或Swagger文檔之類的東西。但是,這是** UGLY **。 –