简体   繁体   中英

Groovy List: Group by by a list of elements

I basically want to group maps, I must group by car and color and sums its prices, if any of the groups prices are greater than 25, group the result by car, color and motor and multiply the sum * 3, first part it's completed, but I'm stuck at the second group by:

def row1 = ["car":'A',"color":'B',"motor":'C', "price": 12]
def row2 = ["car":'A',"color":'B',"motor":'C', "price": 12]
def row3 = ["car":'A',"color":'B',"motor":'D', "price": 2]
def row4 = ["car":'B',"color":'B',"motor":'D', "price": 13]
def arrayRows = []
arrayRows.add(row1)
arrayRows.add(row2)
arrayRows.add(row3)
arrayRows.add(row4)
println(arrayRows) //[[car:A, color:B, motor:C, price:12], [car:A, color:B, motor:C, price:12], [car:A, color:B, motor:D, price:2], [car:B, color:B, motor:D, price:13]]
def groups = arrayRows.groupBy {row -> [Car:row.car, Color:row.color] }.collect{k , v ->
    [
        car:k.Car,
        color:k.Color,
        motor:v.motor,
        price:v.collect { it.price }.sum()
    ]
}
println(groups) //[[car:A, color:B, motor:[C, C, D], price:26], [car:B, color:B, motor:[D], price:13]]
for(group in groups){
    if (group.price > 25){ //26>25
        println group //[car:A, color:B, motor:[C, C, D], price:26]
        //def groupByCarColorMotor = arrayRows.groupBy {[Car: group.car, Color: group.color, Motor:?]} | Must group by car, color and motor, and multiply * 3 it's price but since motor is an array, I'm not sure how to do so, I've tried groupBy { row -> group.it.motor} etc
    }
}

How am I supposed to group by the second time if I have: [car:A, color:B, motor:[C, C, D] And I should group by by: [car:A, color:B, motor:C] And [car:A, color:B, motor:D]

Expected output should be: [ ["car":'A',"color":'B',"motor":'C', "price": 72, ["car":'A',"color":'B',"motor":'D', "price": 6] ]

Edit; I almost managed to do it, the problem is that I'm getting an array of arrays of maps, and also you will probably get the idea behind it too.

def arrayRows = [ 
        ["car":'A',"color":'B',"motor":'C', "price": 12],
        ["car":'A',"color":'B',"motor":'C', "price": 12],
        ["car":'A',"color":'B',"motor":'D', "price": 2],
        ["car":'B',"color":'B',"motor":'D', "price": 13]
        ]

println(arrayRows) //[[car:A, color:B, motor:C, price:12], [car:A, color:B, motor:C, price:12], [car:A, color:B, motor:D, price:2], [car:B, color:B, motor:D, price:13]]
def groups = arrayRows.groupBy {row -> [Car:row.car, Color:row.color] }.collect{k , v ->
    [
            car:k.Car,
            color:k.Color,
            price:v.collect { it.price }.sum()
    ]
}.findAll{it.price > 25}

def groupByCarColor = []
for (group in groups){
    groupByCarColor.add(arrayRows.findAll{ row -> row.car == group.car && row.color == group.color}.groupBy {row -> [Car:group.car, Color:group.color, Motor:row.motor] }.collect{k , v ->
        [
                car:k.Car,
                color:k.Color,
                motor:k.Motor,
                price:v.collect { it.price }.sum()*3
        ]
    })
}

Output: [[[car:A, color:B, motor:C, price:72], [car:A, color:B, motor:D, price:6]]]

Something straight-forward for your home assignment:

def arrayRows = [
["car":'A',"color":'B',"motor":'C', "price": 13],
["car":'A',"color":'B',"motor":'D', "price": 14],
["car":'B',"color":'B',"motor":'D', "price": 13],
]

List out = arrayRows.groupBy{ [ car:it.car, color:it.color ] }.inject( [] ){ List res, k, v ->
  if( 25 < v*.price.sum() ) v.each{ res << ( it + [ price:it.price * 3 ] ) }
  res
}

assert out.toString() == '[[car:A, color:B, motor:C, price:39], [car:A, color:B, motor:D, price:42]]'

Your goal here is to find the groups via a triplet - but you want to filter out those groups where a predicate fails on a subgroup. Eg

def arrayRows = [ 
    [car:'A', motor:'C', color:'B',price: 12],
    [car:'A', motor:'C', color:'B',price: 12],
    [car:'A', motor:'D', color:'B',price:  2],
    [car:'B', motor:'D', color:'B',price: 13],
]


def output = arrayRows.inject([:].withDefault{ 0 }){ acc, row -> // group by the triplet and sum up the price
    acc[row.subMap(['car','motor','color'])]+=row.price; acc
}.groupBy{ k, _ -> // group by the filter criteria tuple
    k.subMap(['car','color'])
}.findAll{ _, v -> // eliminate the tuple-groups where price is to low
    v.values().sum() > 25
}.collectMany{ _, vs -> // reshape the data
    vs.collect{ k, v ->
        k + [price: v * 3]
    }
}

assert output==[[car:"A", motor:"C", color:"B", price:72], [car:"A", motor:"D", color:"B", price:6]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM