Kotlin 切换列表中项目的有效方法

Kotlin Efficient way of Toggling an item in a list

我有一个 toggleItem 算法,其中 removes/adds 项目 from/to 一个 recyclerview 项目列表。它由我的一个朋友优化以减少 !! .

带来的代码味道

我正在寻找替代/最小的方法来编写这个简单的算法,以及我们拥有的很棒的 kotlin 集合操作。除了这两个,你的 optimum/minimal 替代方案是什么?

.

(ItemType 是一个枚举 class,作为初始化项目的标签)

原文:

fun toggleItem(itemType: ItemType, show: Boolean) {
        val item = _allItems.value?.find { it.type == itemType }
        item?.let {
            if (!show) _carouselItems.value = _carouselItems.value!!.minus(it)
        } ?: if (show) _carouselItems.value = _carouselItems.value!!.plus(item!!)

    }

进一步优化:

fun toggleItem(itemType: ItemType, show: Boolean) {
    if (show) {
        val item = _allItems.value?.find { it.type == itemType }
        item?.let {
            _carouselItems.value = _carouselItems.value?.plus(it)?.distinct()?.sortedBy { it.type }
        }
    } else
        _carouselItems.value = _carouselItems.value?.filter { it.type != itemType }
}

我推断 _allItems_carouselItems 都是 MutableLiveData<List<ItemType>?> 或非常相似的类型。您可以将 !! 替换为 Elvis 运算符和默认值,以避免空值安全调用的长链。使用空列表表示没有数据比使用 null 更清楚,所以我会让 LiveData 的类型不可为 null。

在这种情况下,您可以使用 Elvis 运算符进行早期 return / smart-cast 以避免使用 let。在我看来,这种方式更具可读性。

fun toggleItem(itemType: ItemType, show: Boolean) {
    val currentItems = _carouselItems.value ?: emptyList()
    if (show) {
        val item = _allItems.value?.find { it.type == itemType }
            ?: return
        _carouselItems.value = (currentItems + item).distinct().sortedBy { it.type }
    } else
        _carouselItems.value = currentItems.filter { it.type != itemType }
    }
}

如果您知道该项目应该始终在所有项目列表中,这可能会更简洁:

fun toggleItem(itemType: ItemType, show: Boolean) {
    val item = _allItems.value?.find { it.type == itemType }
        ?: return
    val currentItems = _carouselItems.value ?: emptyList()
    _carouselItems.value = when {
            show -> (currentItems + item).distinct().sortedBy { it.type }
            else -> currentItems - item
        }
}

您也可以考虑过渡到 StateFlow。它与 LiveData 的概念类似,只是它强制执行起始值,因此如果类型不可为空,则其 value 参数不可为空。但是你应该先熟悉协程基础知识。

当数据集较小时两者都可以,但随着数据量的增长,计算量会迅速增加。

// store visibility value to a map using ItemType as its keys
val _toggles: Map<ItemType, Boolean> = mapOf(ItemType.One to false, ItemType.Two to true); 

fun toggleItem(itemType: ItemType, show: Boolean) {
    _toggles[itemType] = show
    val list = _allItem.values?.filter(item -> _toggles[item.type]) ?: listOf()
    _carouselItems.value = list
}