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

时间:2012-01-26 18:57:41

标签: groovy group-by maps

如何按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. 团体订单:业余爱好,城市

    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. 团体订单:城市,业余爱好

    London
        poker
            Smith
            Johnson
        design
            Sharma
        chess
            Clark
    LA
        poker
            Maradona
            Waters
        design
            Doe
            Hammond
        chess
            Rogers
    
    HK
        poker
            Ali
            Liu
        design
        chess
            Zhang
    
  3. 修改:

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

    类似的东西:

    1. 对于每个组,打印/输出组名;
    2. 对于组内的每个子组,打印/输出子组名称
    3. 在每个子组内,打印名称。
    4. 它将产生上述结果。

      作为一个好的方面,我想对整个数据结构(组和名称)进行排序。

3 个答案:

答案 0 :(得分:15)

对于第一种情况:

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

和第二个:

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

您最终会在地图中找到原始值,而不仅仅是名称,但您可以这样做:

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

获得结果

["Ali", "Liu"]

btw:这个form of 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有多个参数,就像我在这里使你的代码更具可读性和明显的意图

答案 1 :(得分:2)

如果您希望结果是几个嵌套地图,请尝试以下方法:

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]

答案 2 :(得分:1)

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

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进行测试