如何使用Kotlin扩展函数将多表INNER JOIN结果转换为三级嵌套列表
如何使用Kotlin扩展函数将多表INNER JOIN结果转换为三级嵌套列表
嗨,我完全懂你现在的困扰——从SQL多表联查得到的扁平结果里,手动构建三级嵌套的Category/Feature/Schedule结构确实容易绕晕,而且你之前用collect加Map的方式很容易出错。咱们可以用Kotlin的集合扩展函数来优雅解决这个问题,代码简洁还不容易出错。
首先先明确咱们的输入结构(就是你从数据库拿到的扁平结果类):
// 数据库联查返回的扁平结果类 data class Result( val categoryId: Long, val caption: String, val featureId: Long, val name: String, val rotation: String, val scheduleId: Long, val time: String )
接下来直接给你写核心的扩展函数,专门用来把扁平列表转换成你需要的三级嵌套结构:
// 为List<Result>编写扩展函数,一键转换为三级嵌套列表 fun List<Result>.toNestedCategories(): List<Category> { // 第一步:先按分类ID分组,把同分类的所有数据归到一起 return this.groupBy { it.categoryId } .map { (categoryId, categoryRelatedResults) -> // 第二步:对当前分类下的所有数据,再按功能ID分组 val features = categoryRelatedResults.groupBy { it.featureId } .map { (featureId, featureRelatedResults) -> // 第三步:把当前功能下的所有记录转换成Schedule列表 val schedules = featureRelatedResults.map { Schedule(id = it.scheduleId, time = it.time) } // 组装Feature对象,用first()取重复的name/rotation(同功能下这些值是一致的) Feature( id = featureId, name = featureRelatedResults.first().name, rotation = featureRelatedResults.first().rotation, schedules = schedules ) } // 组装最终的Category对象,同样用first()取重复的caption Category( id = categoryId, caption = categoryRelatedResults.first().caption, features = features ) } }
函数逻辑解释
- 第一层分组:用
groupBy { it.categoryId }把所有扁平结果按分类ID拆分,确保每个分组里的都是同一个分类下的关联数据 - 第二层分组:对每个分类分组,再用
groupBy { it.featureId }拆分出该分类下的所有功能组 - 生成日程列表:每个功能组里的每条记录对应一个日程,用
map直接转换成Schedule对象 - 组装嵌套对象:分别把日程列表组装成
Feature,再把Feature列表组装成Category,因为同分组里的caption/name/rotation都是重复值,用first()取第一个就够了,安全又高效
使用示例
如果是普通列表直接调用:
// 假设这是你从数据库拿到的扁平结果列表 val flatDbResults = listOf( Result(1, "kategorie1", 1, "A1", "0", 10, "10 AM"), Result(1, "kategorie1", 1, "A1", "0", 11, "12 AM"), Result(1, "kategorie1", 2, "A2", "0", 12, "10 AM"), Result(1, "kategorie1", 2, "A2", "0", 13, "12 AM"), Result(2, "kategorie2", 3, "B1", "0", 21, "10 AM"), Result(2, "kategorie2", 4, "B2", "0", 23, "10 AM"), Result(2, "kategorie2", 4, "B2", "0", 25, "12 AM") ) // 调用扩展函数完成转换 val nestedCategories = flatDbResults.toNestedCategories()
如果是用Coroutine Flow的场景,直接在map操作符里调用就行:
// 假设这是你从数据库获取的Flow<List<Result>> val dbResultFlow: Flow<List<Result>> = // 你的数据库查询Flow dbResultFlow .map { it.toNestedCategories() } .collect { nestedList -> // 这里就可以拿到转换好的三级嵌套列表,直接返回给API就行 println("转换后的嵌套结构:$nestedList") }
注意点
- 确保你的
Result类里的字段和数据库查询结果完全对应,尤其是categoryId/featureId这些外键字段不能漏 - 用
first()取重复字段是安全的,因为同分组里的这些值都是来自同一个分类/功能,不会有数据不一致的问题 - 这个扩展函数是纯函数,不会修改原列表,完全符合Kotlin函数式编程的风格
备注:内容来源于stack exchange,提问作者ajeshbaby
相关产品推荐
相关产品推荐

