Stokie
Stokie

Reputation: 35

How to use multiple groupBy and max in Groovy

I am trying to use the Groovy groupBy and max methods to summarise data in my list.

So far I have created a class named allowance which I use to build a list of allowances e.g.

class allowance {
      Integer StartDate
      Integer EndDate
      String  PayCode
      Integer CreatedOn
}

def lAllowances = [
    new allowance(StartDate: 20200330, EndDate: 99991231, PayCode: "PC_DFB1", CreatedOn: 20200330)
   ,new allowance(StartDate: 20200330, EndDate: 99991231, PayCode: "PC_DFB1", CreatedOn: 20200420)
   ,new allowance(StartDate: 20180405, EndDate: 20200329, PayCode: "PC_DFB1", CreatedOn: 20180125)
   ,new allowance(StartDate: 20200330, EndDate: 99991231, PayCode: "PC_DFB2", CreatedOn: 20200330)
   ,new allowance(StartDate: 20100405, EndDate: 99991231, PayCode: "PC_CAR1", CreatedOn: 20100103)
   ]

I now need to group this list and return the latest created allowance based upon CreatedOn for the grouping key (PayCode, StartDate).

I can get it to return what I need with one groupBy closure e.g.

lAllowances.groupBy {it.PayCode}.collectEntries {[(it.key): it.value.max {it.CreatedOn}]}.each{ k,v ->
    mAllowances.put (iCount, [StartDate: v.StartDate, EndDate: v.EndDate, PayCode: k])
    iCount++
}

but when I specify a second closure the max method doesn't seem to work or at least it doesn't return what I thought it would e.g.

lAllowances.groupBy ({it.PayCode},{it.StartDate}).collectEntries {[(it.key): it.value.max {it.CreatedOn}]}.each{ k,v ->
    mAllowances.put (iCount, [StartDate: v.StartDate, EndDate: v.EndDate, PayCode: k])
    iCount++
}

The expected result set after grouping based upon the data above would be something like:

PayCode: "PC_DFB1", StartDate: 20200330, EndDate: 99991231, CreatedOn: 20200420
PayCode: "PC_DFB1", StartDate: 20180405, EndDate: 20200329, CreatedOn: 20180125
PayCode: "PC_DFB2", StartDate: 20200330, EndDate: 99991231, CreatedOn: 20200330
PayCode: "PC_CAR1", StartDate: 20100405, EndDate: 99991231, CreatedOn: 20100103

Any help you can give to resolve this would be greatly appreciated.

Thanks!

Upvotes: 1

Views: 262

Answers (1)

Onno Rouast
Onno Rouast

Reputation: 672

You can concatenate the fields to group by, and then collect with the max closure for each of the matches

def result = lAllowances.groupBy { it.StartDate + it.PayCode }
                        .collect { def matchKey, def matches -> 
                            return matches.max { it.CreatedOn }
                        }

this returns your described result.

If there is a risk of the concatenation creating false matches (e.g 1 + 11 and 11 + 1), you can insert a separator character like | in between.

Upvotes: 1

Related Questions