首页 > 解决方案 > Kotlin - create an object based on sum

问题描述

I have a question. I have the following class

data class Item(val month: Int, val year: Int, val value: Int)

And I have a list

val items = listOf(
    Item(month = 1, year = 2019, value = 5000),
    Item(month = 1, year = 2019, value = 200),
    Item(month = 1, year = 2019, value = 300),
    Item(month = 1, year = 2019, value = 1000),
    Item(month = 2, year = 2019, value = 5000),
    Item(month = 2, year = 2019, value = 6000),
    Item(month = 3, year = 2019, value = 500),
    Item(month = 3, year = 2019, value = 1500),
    Item(month = 5, year = 2019, value = 900),
    Item(month = 1, year = 2020, value = 700)
)

I want to sum values of Item objects having the same month and year, and create another Item object with field month, year and sum as value

val result = listOf(
    Item(month = 1, year = 2019, value = 6500),
    Item(month = 2, year = 2019, value = 11000),
    Item(month = 3, year = 2019, value = 2000),
    Item(month = 5, year = 2019, value = 900),
    Item(month = 1, year = 2020, value = 700)
)

How can I achieve so? Thanks

标签: kotlin

解决方案


首先,您按月 + 年分组(假设这应该是唯一的)。然后将其映射到一个新项目,其中的值是每个组的值。

items.groupBy { "${it.month}/${it.year}" }会给你这样的东西:

{
  '01/2019': [
    Item(month = 1, year = 2019, value = 5000),
    Item(month = 1, year = 2019, value = 200),
    Item(month = 1, year = 2019, value = 300),
    Item(month = 1, year = 2019, value = 1000)
  ],
  '02/2019': ...
}

您现在将此分组映射映射到新项目,您可以在其中value使用所有项目的总和重新计算。生成的代码如下所示:

items.groupBy { "${it.month}/${it.year}" }
     .map {
            Item(it.value.first().month, 
                 it.value.first().year,
                 it.value.sumBy(Item::value))
        }

我的代码中的结果与您的示例输出完全相同。

更新:

为了避免创建字符串和访问第一个数组元素,还有另一种方法。创建您分组的数据对象:

data class Date(var month: Int, var year: Int)

现在您按动态创建的 Date 对象进行分组 - 并解压缩该值:

    items.groupBy({ Date(it.month, it.year) }, { it.value })

这将创建一个这样的地图:

{
    { month: 1, year: 2019 }: [ 5000, 200, 300, 1000 ],
    { month: 2, year: 2019 }: [ ... ]
}

之后,您可以以与以前类似的方式进行映射,但成员访问权限更加清晰:

items.groupBy({ Date(it.month, it.year) }, { it.value })
     .map {
         Item(it.key.month,
              it.key.year,
              it.value.sum())
     }

如果您使用它作为您的项目的基类,您还可以扩展数据类的重用。


推荐阅读