Kotlin如何基于两个不等长列表按分组规则生成目标列表
Kotlin 连续分组匹配类型实现方案
问题说明
给定两个列表:
codes:由若干段连续重复字符串组成的列表,长度未知types:长度和codes的连续重复分组数量一致,每个元素按顺序对应一组重复值的类型
示例输入:
codes = ["or", "or", "or", "parks", "parks", "wa", "wa", "wa", "id"] types = ["STATE", "NATIONAL", "STATE", "STATE"]
需要生成和codes等长的结果列表,每个元素匹配所属分组的类型,上述示例预期结果中共包含7个STATE。
原有实现的问题
你最初写的手动维护游标的for循环思路是对的,但存在一个容易忽略的索引错位bug:初始prevCode为空字符串,遍历第一个codes元素时会触发不等判断,typesIdx从0自增到1,导致第一个分组的元素会错误取到types[1]的值,把初始typesIdx设为-1即可修复这个问题。
符合Kotlin惯用写法的实现
不需要手动维护可变列表和游标,用Kotlin标准库的集合操作函数即可实现,逻辑更清晰也不容易出边界错误:
稳定版实现(兼容所有Kotlin版本)
核心逻辑是先把codes按连续重复值拆分为「值+出现次数」的分组,再和types按顺序对齐,把每个类型重复对应分组的次数后拍平成最终列表:
val result = codes .fold(mutableListOf<Pair<String, Int>>()) { groups, currentCode -> groups.apply { if (lastOrNull()?.first == currentCode) { // 属于当前连续分组,计数+1 val (value, count) = last() set(lastIndex, value to count + 1) } else { // 遇到新的连续分组,初始化计数为1 add(currentCode to 1) } } } // 分组和types按顺序配对,生成对应长度的类型列表 .zip(types) { (_, groupSize), type -> List(groupSize) { type } } // 合并所有子列表,得到和原codes等长的结果 .flatten()
精简版实现(Kotlin 1.6+ 支持)
如果可以使用Kotlin新版本的集合操作API,代码可以进一步精简,不需要显式生成分组计数:
val result = codes .zipWithNext { prev, curr -> prev != curr } .runningFold(0) { index, isNewGroup -> if (isNewGroup) index + 1 else index } .map { types[it] }
结果校验
针对题目给出的示例,上述两种实现的输出均为:
["STATE", "STATE", "STATE", "NATIONAL", "NATIONAL", "STATE", "STATE", "STATE", "STATE"]
其中STATE总数为3+3+1=7,完全符合预期。
内容的提问来源于stack exchange,提问作者Scoobidy-Bop
相关产品推荐
相关产品推荐

