在 Kotlin 中更新特定键的映射值

3

我是一名 Kotlin 的新手,正在努力学习该语言。

我有一个函数,返回 DayofWeek 作为键和一个 Int 值作为值。

我遇到的问题是,我需要获取一个对象列表,其中每个对象内又包含另一个对象列表,该列表具有一个我需要保存并在每次看到相同值时自增的 Int 值。

以下是我的函数 -

class OrdersAnalyzer {
    data class Order(val orderId: Int, val creationDate: LocalDateTime, val orderLines: List<OrderLine>)

    data class OrderLine(val productId: Int, val name: String, val quantity: Int, val unitPrice: BigDecimal)


    fun totalDailySales(orders: List<Order>) : Map<DayOfWeek, Int> {
        val map: MutableMap<DayOfWeek, Int>? = mutableMapOf(
            Pair(DayOfWeek.SUNDAY, 0),
            Pair(DayOfWeek.MONDAY, 0),
            Pair(DayOfWeek.TUESDAY, 0),
            Pair(DayOfWeek.WEDNESDAY, 0),
            Pair(DayOfWeek.THURSDAY, 0),
            Pair(DayOfWeek.FRIDAY, 0),
            Pair(DayOfWeek.SATURDAY, 0)
        )
        for (order in orders) {
            val dayOfWeek = order.creationDate.dayOfWeek
            var quantity = 0

            map?.put(dayOfWeek, quantity)
        }
        return map!!
    }

}

现在我面临的两个问题是 -

1)当当前DayOfWeek时,如何递增每对的值? 我不想替换它,我想将其添加到最后一个值。

2)返回Map时,我不想返回具有0值的DayOfWeeks。我该怎么做?

2个回答

4
这里是优雅回答的一个变种版本,原回答由Arjan提供,并带有一些测试代码。
Alon Shlider的评论后,更新了回答--现在按星期几分组计算所有订单项数量。
fun totalDailySales(orders: List<Order>): Map<DayOfWeek, Int> =
    orders.groupBy { it.creationDate.dayOfWeek }
        .mapValues { sumItemQuantities(it.value) }

fun sumItemQuantities(orders: List<Order>) =
    orders.flatMap { it.orderLines.map { line -> line.quantity } }.sum()

fun main() {
    val orders = listOf(
        Order(
            1,
            LocalDateTime.now().minusDays(2),
            listOf(
                OrderLine(6, "laptop", 28, 1200.toBigDecimal())
            )
        ),
        Order(
            2,
            LocalDateTime.now().minusDays(1),
            listOf(
                OrderLine(496, "VR headset", 6, 400.toBigDecimal())
            )
        )
    )

    println(totalDailySales(orders))
}

输出:

{FRIDAY=28, SATURDAY=6}

通过这种方法,Kotlin函数会自动为您进行分组和计数。groupBy函数将创建一个从DayOfWeek到订单列表的映射(将所有具有相同星期几的订单分组到一个列表中)。mapValues函数通过用sumItemQuantities函数的结果替换列表来转换该映射(对于每个列表)。

在您的代码中的for循环中,您可以检索特定日期的当前数量(如果尚未设置,则使用零),将其增加适当的数量,然后存储它。要仅返回具有非零值的映射条目,您可以过滤(返回totalsPerDay.filter { it.value > 0 })或从空映射开始。以下是带有一些更改的函数:

fun totalDailySales(orders: List<Order>): Map<DayOfWeek, Int> {
    val totalsPerDay = mutableMapOf<DayOfWeek, Int>()

    for (order in orders) {
        val dayOfWeek = order.creationDate.dayOfWeek
        val currentQuantity = totalsPerDay[dayOfWeek] ?: 0

        // This is not the best way to increment by the sum of the order
        // item quantities...
        val orderItemQuantities = sumItemQuantities(listOf(order))
        totalsPerDay[dayOfWeek] = currentQuantity + orderItemQuantities
    }

    return totalsPerDay
}

调用后的输出结果:
println(OrdersAnalyzer().totalDailySales(orders))

{FRIDAY=28, SATURDAY=6}

谢谢你的帮助。不过,你的解决方案并没有给出正确的答案。它计算了每天被提及的次数,而期望的结果是计算该天的总数量。 - Alon Shlider
@AlonShlider 你是指所有订单行中数量的总和吗? - Arjan
@Arjan 是的,那就是我的意思。 - Alon Shlider
2
@AlonShlider 不用谢。我也更新了我的回答。很好的合作努力... :-) - Freek de Bruijn

3

更新的答案(还要感谢Freek de Bruijn),附上一些测试代码。

我认为应该是这样的:

fun totalDailySales(orders: List<Order>) : Map<DayOfWeek, Int> =
    orders.groupBy { it.creationDate.dayOfWeek }
        .mapValues { it.value.flatMap { it.orderLines } }
        .mapValues { it.value.map { it.quantity } }
        .mapValues { it.value.sum() }

groupBy创建一个Map,其中值的类型为List<Order>,因此您需要调用几个步骤将这些值转换为Int。首先,我们使用flatMapList<Order>转换为List<OrderLine>map会转换为List<List<OrderLine>>)。然后,我们使用mapList<OrderLine>中获取数量,最后使用sum()将所有这些数量相加。

val orders = listOf(
    Order(
        2,
        LocalDateTime.now().minusDays(2),
        listOf(
                OrderLine(5, "monitor", 10, 200.toBigDecimal()),
                OrderLine(4, "keyboard", 5, 50.toBigDecimal())
        )
    )

)

println(totalDailySales(orders))

这将导致以下输出:
{FRIDAY=15}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接