user2782001 user2782001 - 1 month ago 10
Groovy Question

Groovy way of grouping by more than one property only one level deep

I want to group by 3 properties but not have each property be it's own nested array. What I want:

def values=[
[day:1,month:1,year:1],
[day:1,month:1,year:1],
[day:2,month:1,year:1],
[day:2,month:2,year:1]
];

/*...some code to group by DAY, MONTH, AND YEAR

..desired result is that items with the same day,
month, and year end up in a one level deep subarray
*/

[
[[day:1,month:1,year:1],[day:1,month:1,year:1]],
[[day:2,month:1,year:1]] ,
[[day:2,month:2,year:1]]
];


Using the groupBy() method with multiple closures gives me each grouped property as its own nested array, like [ year [ month [ day [ ] ] ] ], which is not what I need.

Answer

Consider the following use of inject to build up a map whose keys are the appropriate group, and values are the desired lists:

def values=[
     [day:1,month:1,year:1],
     [day:1,month:1,year:1],
     [day:2,month:1,year:1],
     [day:2,month:2,year:1]
 ];

def groupMap = [:].withDefault{ key -> [] }

def result = values.inject(groupMap) { val, m -> 
    val["${m.'day'}${m.'month'}${m.'year'}"] << m 
    val
}.values()

assert [[day:1, month:1, year:1], [day:1, month:1, year:1]] == result[0]
assert [[day:2, month:1, year:1]] == result[1]
assert [[day:2, month:2, year:1]] == result[2]
Comments