Kotlin:用集合前一项值填充当前项的null字段
用Kotlin的scan函数填充列表中null的name字段(持续传递前值)
问题描述
给定如下Kotlin数据类:
data class MyObject(val name: String?, val age: Int)
需要遍历该类的对象列表,将其中name == null的项替换为前一项已处理后的name值(如果存在),替换效果持续传递:比如第0项有name,第1、2项无name时,第1项取第0项的name,第2项取已替换后的第1项的name。
示例输入:
val inputList = listOf( MyObject("Paul", 21), MyObject(null, 23), MyObject(null, 17), MyObject("Mike", 45), MyObject("Laura", 20), MyObject(null, 60) )
期望输出:
listOf( MyObject("Paul", 21), MyObject("Paul", 23), MyObject("Paul", 17), MyObject("Mike", 45), MyObject("Laura", 20), MyObject("Laura", 60) )
解决方案:使用scan函数实现
Kotlin的scan函数天生适合这种需要累积状态并保留每一步结果的场景。我们可以用它跟踪当前有效的name值,同时生成处理后的对象:
fun fillNullNames(list: List<MyObject>): List<MyObject> { if (list.isEmpty()) return emptyList() return list.scan(Pair<String?, MyObject?>(null, null)) { (lastValidName, _), current -> // 优先使用当前项的name,否则取上一个有效name val validName = current.name ?: lastValidName // 更新累积的有效name,并生成处理后的对象 validName to current.copy(name = validName) } .drop(1) // 移除scan初始的占位Pair(null, null) .map { it.second } .filterNotNull() // 过滤理论上不会出现的null }
代码说明
- 累积状态设计:用
Pair<String?, MyObject?>保存两个核心状态:lastValidName记录上一个非null的name值,第二个元素是当前处理完成的MyObject。 - 核心逻辑:对每个元素,若自身name为空则复用累积的有效name,否则更新累积的有效name为自身name,同时生成新的MyObject。
- 结果清理:
drop(1)去掉scan初始化的占位项,最终提取出完整的处理后列表。
调用示例
val inputList = listOf( MyObject("Paul", 21), MyObject(null, 23), MyObject(null, 17), MyObject("Mike", 45), MyObject("Laura", 20), MyObject(null, 60) ) val outputList = fillNullNames(inputList) // 输出结果与示例期望完全一致
非空列表的简洁写法
如果能确保输入列表不为空,还可以简化初始值处理:
val firstItem = inputList.first() val result = listOf(firstItem) + inputList.drop(1).scan(firstItem.name) { prevName, item -> item.name ?: prevName }.mapIndexed { index, validName -> inputList.drop(1)[index].copy(name = validName) }
内容的提问来源于stack exchange,提问作者M Rajoy
相关产品推荐
相关产品推荐

