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
}
我有一个 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
}