首页 > 解决方案 > Kotlin 从列表中获取 x 个元素,但首先删除最小的数字

问题描述

所以想象你有一堂课Product。在这个类中,有一个mutablelistOf<Stock>(). 该类Stock包含两个属性:一个属性是quantitystock has ,另一个是amount of stars. mutabeListOf<Stock>()按升序排序(列表中的amount of stars第一个股票有 1 星,然后是 2,然后是 3...)。

现在有一个客户想要从 Product 列表中取出 5 件商品(客户减少了数量属性)。顾客应先从星数最少的Stock物品 取走。如上所述,星数最少的股票位于列表的开头。在客户拿走这 5 件商品后,Stock 对象的数量属性应该减少,并且当它的数量属性为 0 时,该对象应该从列表中删除。

另一种情况是没有足够的物品要带走(例如,客户想要 15 个物品,但总共有 10 个)。在这种情况下,应取最大金额(10),并退回客户取走的金额(例如,此处为 10)。

我知道如何删除这些项目,但是当我删除它们时,数量会低于 0,并且 for 循环不会“跳转”到下一个 Stockobject。

这是我目前的方法:Class Stock

class Stock(var quantity: Int, val stars: Int) {
    init {
        if (quantity < 0) quantity = 0
    }
}

类 Product 和函数 takeItems:

class Product {
    private val stockList = mutableListOf<Stock>()
    val availableItems: Double
        get() {
            return stockList.map { it.quantity.toDouble() }.sum()
        }

    fun addStock(item: Stock) = stockList.add(item)
    fun enoughItemsAvailable(itemQuantity: Int): Boolean = availableItems >= itemQuantity

    // The function I am trying to create to take items out of the list
    fun takeItems(quantity: Int): Int {
        stockList.sortBy { it.stars }

        var taken = 0
        for (i in stockList.indices) {
            if (stockList[i].quantity == 0) stockList.removeAt(i)
            if (enoughItemsAvailable(quantity)) {
                do {
                    stockList[i].quantity -= quantity
                    taken++
                } while (stockList[i].quantity > 0 || taken != quantity)
            } else {
                // when there is not enough items to be taken
                stockList.clear()
                return quantity
            }
        }
        return taken
    }

我希望你们理解我的问题。我感谢每一个帮助!

标签: listsortingkotlin

解决方案


在您的代码中,您从列表中的第一个库存中获取全部请求的数量,即使这导致它的数量为负。我认为您应该 putstockList[i].quantity--而不是stockList[i].quantity -= quantity,因为您的策略似乎是一次删除一个。

此外,如果 Stock 为空,则循环中的第一行将删除它,然后下一部分开始从下一个 Stock 中删除,而无需先检查它是否为空。如果连续两只股票为空怎么办?所以第一个if应该是while.

IndexOutOfBoundsException但是由于您在迭代其索引时从列表中删除,如果有任何项目被删除,您将到达。因此,您需要if (i >= stockList.size) break在循环的开头添加。

您对是否有足够的项目来满足完整请求的检查可以移到循环之外,以避免一遍又一遍地重复检查该条件。

我认为一个更简单的策略是遍历列表,从每个列表中获取尽可能多的内容,Stock直到您获取足够的列表或用尽列表。然后用一行删除列表中的空 Stocks。这样,您就不需要单独的逻辑分支来处理不足以满足请求的情况,并且您不需要单独检查任何 Stocks 是否已经为空。

fun takeItems(quantity: Int): Int {
    stockList.sortBy { it.stars }

    var taken = 0
    for (stock in stockList) {
        val toRemove = min(quantity - taken, stock.quantity)
        taken += toRemove
        stock.quantity -= toRemove
        if (quantity == taken) break
    }

    stockList.removeAll { it.quantity == 0 }

    return taken
}

顺便说一句,它看起来availableItems应该是Int,而不是Double,因为它是项目的计数。它可以更有效地完成

    val availableItems: Int
        get() = stockList.sumBy(Stock::quantity)

因为 usingmap每次访问此属性时都会创建一个新列表。


推荐阅读