Groovy 如何基于两个键对贴图值求和?

Groovy 如何基于两个键对贴图值求和?,groovy,Groovy,我有一张地图,上面有两个键(customer和price),如下所示: [ customer: ['Clinton', 'Clinton', 'Mark', 'Antony', 'Clinton', 'Mark'], price: [15000.0, 27000.0, 28000.0, 56000.0, 21000.0, 61000.0] ] customer和price值通过其索引位置映射,即customer列表中的名字与第一个价格映射,依此类推 范例 Cliton pri

我有一张地图,上面有两个键(
customer
price
),如下所示:

[
    customer: ['Clinton', 'Clinton', 'Mark', 'Antony', 'Clinton', 'Mark'], 
    price: [15000.0, 27000.0, 28000.0, 56000.0, 21000.0, 61000.0]
]
customer
price
值通过其索引位置映射,即
customer
列表中的名字与第一个价格映射,依此类推

范例

Cliton price is 15000.0
Cliton price 27000.0
Mark price 28000.0
Antony price 56000.0
Clinton price 21000.0
Mark price 61000.0
我想把价格按名称分类汇总一下。预期产出:

Clinton price 63000
Mark price 89000
Antony price 56000

Groovy中是否有任何内置函数来实现这一点,或者我是否需要通过编写自己的函数来迭代映射和求和值?

下面的内容创建了一个由
客户
聚合的
价格的映射:

def vals = (0..(-1+map.customer.size()))
           .collect{['name':map.customer[it], 'price': map.price[it]]}
           .groupBy{it['name']}
           .collectEntries{[(it.key): it.value.collect{it['price']}.sum()]}
这导致:

[Clinton:63000.0, Mark:89000.0, Antony:56000.0]

它本质上是一个迭代,使用从
0
map.customer.size()-1
的一系列数字,然后是一组带值和的by。

在这样的问题中,我们应该始终计划将每个条目作为列表中的单独对象,以使其在列表中直观且易于操作

在这种情况下,同样的结果也可以自然得到

def list = [

        [customer: 'Clinton', price: 15000.0],
        [customer: 'Clinton', price: 27000.0],
        [customer: 'Mark',    price: 28000.0],
        [customer: 'Antony',  price: 56000.0],
        [customer: 'Clinton', price: 21000.0],
        [customer: 'Mark',    price: 61000.0]
]


def map = list.groupBy({it.customer}).collectEntries {k, v -> [k, v.price.sum()]}

map.each {println it}

您可以从两个列表上的转置开始,以获得customer和price的元组。从这里开始,它基本上与其他答案类似(按客户分组,与客户一起构建地图并汇总价格)。例如:


这个版本是从@cfrick的答案中派生出来的,除了求和之外还有一个选择。使用带有默认值的映射并不是“功能性的”/“声明性的”,但可以说,以后更容易查找代码(即维护):

鉴于:

def map = [
    customer: ['Clinton', 'Clinton', 'Mark', 'Antony', 'Clinton', 'Mark'],
    price: [15000.0, 27000.0, 28000.0, 56000.0, 21000.0, 61000.0]
]
方法:

def getSumMap = { data ->
    def result = [:].withDefault { c -> 0.0 }

    [data.customer, data.price].transpose().each { c, p -> result[c] += p }

    result
}

assert 63000.0 == getSumMap(map)['Clinton']
assert 89000.0 == getSumMap(map)['Mark']
assert 56000.0 == getSumMap(map)['Antony']

我猜OP的问题是因为他收到了一张给定格式的地图。如果您提供将输入格式转换为您提供的格式的方法,您的答案会更好。好的。这是一个要点。在这种情况下,它与@cfrick的解决方案相同谢谢。我得到的数值低于这个数值[Clinton:15000.0,Clinton:27000.0,Mark:28000.0,Antony:56000.0,Clinton:21000.0,Mark:61000.0]谢谢。我发现以下错误:groovy.lang.MissingMethodException:没有方法签名:java.math.BigDecimal.plus()适用于参数类型:(groovy.util.slurpersupport.NodeChild)值:[15000.0]可能的解决方案:plus()、plus(java.math.MathContext)、plus(java.lang.Character)、plus(java.lang.Number)、plus(java.lang.String)、ulp()groovy.lang.MissingMethodException:没有方法签名:java.math.BigDecimal.plus()适用于参数类型:(groovy.util.slurpersupport.NodeChild)值:[15000.0]答案适用于groovy 2.4.9。我已经把它贴在这里了-。。。您使用的是什么版本的Groovy和Java?
def getSumMap = { data ->
    def result = [:].withDefault { c -> 0.0 }

    [data.customer, data.price].transpose().each { c, p -> result[c] += p }

    result
}

assert 63000.0 == getSumMap(map)['Clinton']
assert 89000.0 == getSumMap(map)['Mark']
assert 56000.0 == getSumMap(map)['Antony']