【问题标题】:Kotlin collections and objects sumKotlin 集合和对象总和
【发布时间】:2021-05-27 19:20:27
【问题描述】:

我有以下课程:

class UserData(
        val firstSale: Date,
        val lastSale: Date,
        val ptuCodesList: List<ItemSale>,
        val taxList: List<ItemSale>,
        val salesList: List<ItemSale>,
        val taxTotal: Long,
        val saleTotal: Long,
        val currency: String = DEAFULT_CURRENCY,
        val canceledOrderCount: Int,
        val canceledSaleTotal: Long,
)

和模型类:

class ItemSale(
       val itemDescription: String,
       val itemsTotalValue: Long
)

我正在从我的数据库中获取我所有的 UserData 对象

dbRepository.getAllUsersData(): List<UserData>

现在我不知道如何对这个 List UserData 对象求和并作为单个对象返回,我的意思是,我不知道如何对包含在 UserData 对象中的那些列表 taxList/saleList 求和。在这些列表中,我需要对 itemsTotalValue 求和。

例子:

我们有两个 UserData 对象的列表:

class UserData(
        val firstSale: 238402384092L,
        val lastSale: 893231117482L,
        val ptuCodesList: List<ItemSale>,
        val taxList: List<ItemSale>, -> ("first", 4), ("second", 4)
        val salesList: List<ItemSale>, -> ("third", 5), ("fourth", 3)
        val taxTotal: 500,
        val saleTotal: 600,
        val currency: String = DEAFULT_CURRENCY,
        val canceledOrderCount: 3,
        val canceledSaleTotal: 4500
)

class UserData(
        val firstSale: 338402384092L,
        val lastSale: 9934798237482L,
        val ptuCodesList: List<ItemSale>,
        val taxList: List<ItemSale>, -> ("first", 7), ("second", 8)
        val salesList: List<ItemSale>, -> ("third", 1), ("fourth", 2)
        val taxTotal: 250,
        val saleTotal: 400,
        val currency: String = DEAFULT_CURRENCY,
        val canceledOrderCount: 4,
        val canceledSaleTotal: 400
)

结果:

class UserData(
        val firstSale: 238402384092L,
        val lastSale: 9934798237482L,
        val ptuCodesList: List<ItemSale>, //Stay same for all objects
        val taxList: List<ItemSale>, // ("first", 11), ("second", 12)
        val salesList: List<ItemSale>, // ("third", 6), ("fourth", 5)
        val taxTotal: 750,
        val saleTotal: 1000,
        val currency: String = DEAFULT_CURRENCY, // Stay for all same
        val canceledOrderCount: 7,
        val canceledSaleTotal: 4900
)

谢谢

【问题讨论】:

    标签: android kotlin collections


    【解决方案1】:

    目前还不清楚当“求和”两个具有不同 firstSalelastSalecurrency 的 UserData 时您希望发生什么。无论如何,我会编写一个将两个 UserData 加在一起的函数,以您想要的方式处理这些情况,例如:

    fun List<ItemSale>.aggregateWith(other: List<ItemSale>): List<ItemSale> {
        return (this + other).groupBy(ItemSale::itemDescription)
            .entries
            .map { ItemSale(it.key, it.value.map(ItemSale::itemsTotalValue).sum() )}
    }
    
    data class UserData(
        val firstSale: Date,
        val lastSale: Date,
        val ptuCodesList: List<ItemSale>,
        val taxList: List<ItemSale>,
        val salesList: List<ItemSale>,
        val taxTotal: Long,
        val saleTotal: Long,
        val currency: String,
        val canceledOrderCount: Int,
        val canceledSaleTotal: Long,
    ) {
        operator fun plus(other: UserData): UserData {
            if (other.firstSale != firstSale || other.lastSale != lastSale || other.currency != currency) {
                error("Cannot add mismatched UserData $this to $other.")
            }
            return copy(
                ptuCodesList = ptuCodesList.aggregateWith(other.ptuCodesList),
                taxList = taxList.aggregateWith(other.taxList),
                salesList = salesList.aggregateWith(other.salesList),
                taxTotal = taxTotal + other.taxTotal,
                saleTotal = saleTotal + other.saleTotal,
                canceledOrderCount = canceledOrderCount + other.canceledOrderCount,
                canceledSaleTotal = canceledSaleTotal + other.canceledSaleTotal
            )
        }
    }
    

    那么你就可以reduce列表来获取你想要的:

    fun List<UserData>.aggregate(): UserData = reduce(UserData::plus)
    

    【讨论】:

    • 第一次销售我将从列表中的第一项获取,但最后一次销售日期我将从列表中的最后一个对象获取,其中一些变量将保持不变,例如:ItemSale 中的 itemDescription
    • 好的,那么你能从我输入的内容中弄清楚吗?只需修改plus 函数以在组合两个对象时执行您想要的操作。
    • 我再次编辑了我的示例,使其更加具体。但我无法从你的回答中弄清楚如何实现我的目标。抱歉,我在 kotlin 方面还不是很好 :(
    【解决方案2】:

    可能是这样的:

      listOfUserData.map{ it.salesList.map{ it.itemsTotalValue }.sum() }.sum()
    

    一个简化但完整的例子:

    class UserData(val salesList: List<ItemSale>, val taxList: List<ItemSale>)
    
    class ItemSale(
       val itemDescription: String,
       val itemsTotalValue: Long
    )
    
    fun main() {
    
        val itemSale1 = ItemSale("A", 12) 
        val itemSale2 = ItemSale("B", 30) 
        val itemSale3 = ItemSale("C", 45) 
        val itemSale4 = ItemSale("D", 55)
        val itemSale5 = ItemSale("E", 23)
        val itemSale6 = ItemSale("F",  2)
    
        val listOfUserData = listOf(UserData(listOf(itemSale1, itemSale2), 
                                             listOf(itemSale5)),
                                    UserData(listOf(itemSale3, itemSale4), 
                                             listOf(itemSale6)) )
    
        val sumSales = listOfUserData.map{ it.salesList.map{ it.itemsTotalValue }.sum() }.sum()
        val sumTax   = listOfUserData.map{ it.taxList.map{ it.itemsTotalValue }.sum() }.sum() 
    
        val sum      = listOfUserData.map{ it.salesList.map{ it.itemsTotalValue }.sum() }.sum() + 
                       listOfUserData.map{ it.taxList.map{ it.itemsTotalValue }.sum() }.sum()       
    
    
        println(sumSales)   // 142
        println(sumTax)     //  25 
        println(sum)        // 167
    
     }
    

    合并对象的更新:

     val itemSale1 = ItemSale("A", 12)
     val itemSale2 = ItemSale("B", 30)
     val itemSale3 = ItemSale("C", 45)
     val itemSale4 = ItemSale("D", 55)
     val itemSale5 = ItemSale("A", 13)
     val itemSale6 = ItemSale("B", 29)
     val itemSale7 = ItemSale("C", 32)
     val itemSale8 = ItemSale("D", 21)
    
     val myMap = mutableMapOf<String, Long>()
    
     val listOfUserData = listOf(UserData(listOf(itemSale1, itemSale2),
                                          listOf(itemSale3, itemSale4)),
                                 UserData(listOf(itemSale5, itemSale6),
                                          listOf(itemSale7, itemSale8)) )
    
     listOfUserData.map{ it.salesList.map{ myMap[it.itemDescription] = myMap.getOrDefault(it.itemDescription, 0L) + it.itemsTotalValue }}
    
     println(myMap)   // {A=25, B=59}
    

    科特林游乐场

    https://pl.kotl.in/aiGawyaJQ

    【讨论】:

    • 我在我的问题中添加了示例以便更好地理解:)
    • 重点是,列表大小不是固定的,可以是0..n
    • 所有这些对象的字符串描述都是不变的,但值不是
    • 另一个想法:将变量读入地图 - 请参阅帖子中的更新部分。
    【解决方案3】:

    您可以使用sumByDouble

    class UserData(
        val firstSale: Date,
        val lastSale: Date,
        val ptuCodesList: List<ItemSale>,
        val taxList: List<ItemSale>,
        val salesList: List<ItemSale>,
        val taxTotal: Long,
        val saleTotal: Long,
        val currency: String = DEAFULT_CURRENCY,
        val resignOrderCount: Int,
        val canceledSaleTotal: Long,
        val fiscalEventsCount: Int,
        val nonFiscalPrintoutsCount: Int
    ){
        val sumOfTaxAndSales: Long
          get() = taxList.sumByDouble { it.itemsTotalValue.toDouble() }.toLong() + salesList.sumByDouble { it.itemsTotalValue.toDouble() }.toLong()
    }
    

    【讨论】:

    • 我不需要将 taxList 添加到 saleList。我需要对 UserData 列表中的所有数字进行 1:1 的总和,包括 (itemsTotalValue) 嵌套列表中的数字
    • 你能添加例子来阐述你的期望吗?
    • 我稍微改变了我的班级,并添加了示例。希望它有所帮助:)
    【解决方案4】:

    如果你想保持 Long 作为你的求和结果,你可以使用 map 函数。例如:

    val taxListSum = taxList.map { it.itemsTotalValue }.sum()
    

    我建议这样做,因为到目前为止 Kotlin 只提供 sumBy(它返回一个 Int)和 sumByDouble 来对集合的具体属性求和。

    【讨论】:

    • 我在我的问题中添加了示例以简化我的问题:)
    猜你喜欢
    • 1970-01-01
    • 2016-02-17
    • 2023-03-10
    • 1970-01-01
    • 2010-09-20
    • 1970-01-01
    • 2011-01-07
    • 1970-01-01
    • 2021-11-01
    相关资源
    最近更新 更多