Groovy:如何按 2 个不同的标准对地图值进行分组?

发布于 2024-12-28 22:52:18 字数 1424 浏览 3 评论 0原文

如何按 2 个不同的标准对地图值进行分组以获得以下输出?

def listOfMaps = [
  [name:'Clark', city:'London', hobby: 'chess'], [name:'Sharma', city:'London', hobby: 'design'],
  [name:'Maradona', city:'LA', hobby: 'poker'], [name:'Zhang', city:'HK', hobby: 'chess'],
  [name:'Ali', city: 'HK', hobby: 'poker'], [name:'Liu', city:'HK', hobby: 'poker'],
  [name:'Doe', city:'LA', hobby: 'design'], [name:'Smith', city:'London', hobby: 'poker'],
  [name:'Johnson', city: 'London', hobby: 'poker'], [name:'Waters', city:'LA', hobby: 'poker'],
  [name:'Hammond', city:'LA', hobby: 'design'], [name:'Rogers', city:'LA', hobby: 'chess'],
]
  1. 团体顺序:爱好、城市

    扑克
        伦敦
            史密斯
            约翰逊
        洛杉矶
            马拉多纳
            沃特斯
        香港
            阿里
            刘
    设计
        伦敦
            夏尔马
        洛杉矶
            美国能源部
            哈蒙德
        香港
    棋
        伦敦
            克拉克   
        洛杉矶
            罗杰斯
        香港
            张   
    
  2. 团体顺序:城市、爱好

    伦敦
        扑克
            史密斯
            约翰逊
        设计
            夏尔马
        棋
            克拉克
    洛杉矶
        扑克
            马拉多纳
            沃特斯
        设计
            美国能源部
            哈蒙德
        棋
            罗杰斯
    
    香港
        扑克
            阿里
            刘
        设计
        棋
            张
    

编辑:

我真正需要的是迭代的方法,以有效地循环组结构,并能够构造结果(组/子组/名称)。

类似于:

  1. 对于每个组,打印/输出组名称;
  2. 对于组内的每个子组,打印/输出
  3. 每个子组内的子组名称,打印名称。

它将产生上面概述的结果。

顺便说一句,我想对整个数据结构(组和名称)进行排序。

How can I group map values by 2 different criteria to get the outputs below ?

def listOfMaps = [
  [name:'Clark', city:'London', hobby: 'chess'], [name:'Sharma', city:'London', hobby: 'design'],
  [name:'Maradona', city:'LA', hobby: 'poker'], [name:'Zhang', city:'HK', hobby: 'chess'],
  [name:'Ali', city: 'HK', hobby: 'poker'], [name:'Liu', city:'HK', hobby: 'poker'],
  [name:'Doe', city:'LA', hobby: 'design'], [name:'Smith', city:'London', hobby: 'poker'],
  [name:'Johnson', city: 'London', hobby: 'poker'], [name:'Waters', city:'LA', hobby: 'poker'],
  [name:'Hammond', city:'LA', hobby: 'design'], [name:'Rogers', city:'LA', hobby: 'chess'],
]
  1. group order : hobby, city

    poker
        London
            Smith
            Johnson
        LA
            Maradona
            Waters
        HK
            Ali
            Liu
    design
        London
            Sharma
        LA
            Doe
            Hammond
        HK
    chess
        London
            Clark   
        LA
            Rogers
        HK
            Zhang   
    
  2. group order : city, hobby

    London
        poker
            Smith
            Johnson
        design
            Sharma
        chess
            Clark
    LA
        poker
            Maradona
            Waters
        design
            Doe
            Hammond
        chess
            Rogers
    
    HK
        poker
            Ali
            Liu
        design
        chess
            Zhang
    

Edit :

What I really need is the way to iterate to effectively loop through the group structure, and be able to construct the result (group / subgroup / name ).

Something like :

  1. for each group, print/output the group name;
  2. for each subgroup inside a group, print/output the subgroup name
  3. inside each subgroup, print the names.

It would yield the result outlined above.

As a nice aside, I would like to sort the whole data structure (groups and names).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

强者自强 2025-01-04 22:52:18

对于第一种情况:

result = map.groupBy( { it.hobby }, { it.city } )

对于第二种情况:

result = map.groupBy( { it.city }, { it.hobby } )

您最终会得到地图中的原始值而不仅仅是名称,但您将能够执行以下操作:

result[ 'poker' ][ 'HK' ].name

获得结果

["Ali", "Liu"]

顺便说一句:此 groupBy 的形式有自 Groovy 以来才可用1.8.1,所以如果你坚持使用早期版本,这将不起作用

编辑2

根据你下面的评论,你可以这样做:

result.each { a, b ->
  println "$a"
  b.each { c, d ->
    println "  $c"
    d.each {
      println "    $it.name"
    }
  }
}

这与GVdP在他的回答中的逻辑相同,但我觉得使用像我这里一样具有多个参数的 groupBy 使您的代码更具可读性并且其意图更明显

For the first case:

result = map.groupBy( { it.hobby }, { it.city } )

and for the second:

result = map.groupBy( { it.city }, { it.hobby } )

You will end up with the original values in the map rather than just the name, but you will be able to do:

result[ 'poker' ][ 'HK' ].name

to get the result

["Ali", "Liu"]

btw: This form of groupBy has only been available since Groovy 1.8.1, so if you're stuck on an earlier version, this won't work

edit 2

Based on your comment below, you can then do:

result.each { a, b ->
  println "$a"
  b.each { c, d ->
    println "  $c"
    d.each {
      println "    $it.name"
    }
  }
}

This is the same logic as GVdP had in his answer, but I feel using the groupBy with multiple parameters like I have here makes your code more readable and obvious as to its intent

等往事风中吹 2025-01-04 22:52:18

如果您希望结果是几个嵌套的映射,请尝试以下操作:

def byHobbyCity = map.groupBy{it.hobby}.collectEntries{k, v -> [k, v.groupBy{it.city}]}
def byCityHobby = map.groupBy{it.city}.collectEntries{k, v -> [k, v.groupBy{it.hobby}]}

println byHobbyCity['chess']['London']*.name
==> [Clark]

println byCityHobby['London']['chess']*.name
==> [Clark]

If you want the result to be a couple of nested maps, try something like this:

def byHobbyCity = map.groupBy{it.hobby}.collectEntries{k, v -> [k, v.groupBy{it.city}]}
def byCityHobby = map.groupBy{it.city}.collectEntries{k, v -> [k, v.groupBy{it.hobby}]}

println byHobbyCity['chess']['London']*.name
==> [Clark]

println byCityHobby['London']['chess']*.name
==> [Clark]
谎言月老 2025-01-04 22:52:18

根据您的评论回答,这将按照您的要求进行:

def listOfMaps = [
  [name:'Clark', city:'London', hobby: 'chess'], [name:'Sharma', city:'London', hobby: 'design'],
  [name:'Maradona', city:'LA', hobby: 'poker'], [name:'Zhang', city:'HK', hobby: 'chess'],
  [name:'Ali', city: 'HK', hobby: 'poker'], [name:'Liu', city:'HK', hobby: 'poker'],
  [name:'Doe', city:'LA', hobby: 'design'], [name:'Smith', city:'London', hobby: 'poker'],
  [name:'Johnson', city: 'London', hobby: 'poker'], [name:'Waters', city:'LA', hobby: 'poker'],
  [name:'Hammond', city:'LA', hobby: 'design'], [name:'Rogers', city:'LA', hobby: 'chess'],
]

listOfMaps.groupBy {it.hobby}.each { k,v ->
 println k
 v.groupBy {it.city}.each {k1, v1->
  println "  $k1"
  v1.each {
   println "    $it.name"
  }
 }
}

用 Groovy 1.7.10 测试

Answering based on your comments, this will do as you ask:

def listOfMaps = [
  [name:'Clark', city:'London', hobby: 'chess'], [name:'Sharma', city:'London', hobby: 'design'],
  [name:'Maradona', city:'LA', hobby: 'poker'], [name:'Zhang', city:'HK', hobby: 'chess'],
  [name:'Ali', city: 'HK', hobby: 'poker'], [name:'Liu', city:'HK', hobby: 'poker'],
  [name:'Doe', city:'LA', hobby: 'design'], [name:'Smith', city:'London', hobby: 'poker'],
  [name:'Johnson', city: 'London', hobby: 'poker'], [name:'Waters', city:'LA', hobby: 'poker'],
  [name:'Hammond', city:'LA', hobby: 'design'], [name:'Rogers', city:'LA', hobby: 'chess'],
]

listOfMaps.groupBy {it.hobby}.each { k,v ->
 println k
 v.groupBy {it.city}.each {k1, v1->
  println "  $k1"
  v1.each {
   println "    $it.name"
  }
 }
}

Tested with Groovy 1.7.10

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文