You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使Kotlin数据类的declaredMemberProperties保持定义顺序用于CSV导出

解决Kotlin数据类转CSV时保持字段定义顺序的问题

问题描述

Android应用中用多个数据类对应数据库表,需要把数据导出为CSV格式,但当前用declaredMemberProperties遍历属性时,字段会按字母顺序排序,没法保持数据类里的定义顺序。另外之前的方案还存在无法获取属性具体值的问题。

数据类示例:

data class Table1(
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0,
    var dataA: String,
    var dataH: String,
    var dataB: String
)

data class Table2(
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0,
    var dataG: String,
    var dataC: String,
    var dataD: String
)

当前实现的函数输出会是字母排序的结果(比如A;B;H;0;),但期望按数据类定义顺序输出(比如0;A;H;B;)。

解决方案

利用Kotlin数据类的primaryConstructor获取字段定义顺序——数据类主构造函数的参数顺序和类中字段定义顺序完全一致。遍历主构造函数参数,再映射到对应的成员属性取值,就能保持原有顺序。

修改后的函数实现:

fun datatableToStrings(tableDatasets: List<Any>): String {
    if (tableDatasets.isEmpty()) return ""
    
    val kClass = tableDatasets[0].javaClass.kotlin
    // 仅支持数据类,确保能获取主构造函数参数
    require(kClass.isData) { "仅支持数据类转换" }
    
    val primaryConstructor = kClass.primaryConstructor ?: return ""
    val properties = primaryConstructor.parameters.mapNotNull { param ->
        kClass.declaredMemberProperties.find { it.name == param.name }
    }
    
    val bufferList = mutableListOf<StringBuilder>().apply {
        add(StringBuilder()) // 表头行
        repeat(tableDatasets.size) { add(StringBuilder()) } // 数据行
    }
    
    // 填充表头和数据
    properties.forEach { prop ->
        // 添加表头
        bufferList[0].append("${prop.name};")
        // 添加每行数据
        tableDatasets.forEachIndexed { index, item ->
            val value = prop.get(item).toString()
            bufferList[index + 1].append("$value;")
        }
    }
    
    // 拼接所有行
    return bufferList.joinToString(separator = "\n") { it.toString() }
}

代码说明

  1. 数据类校验:先判断输入对象是否为数据类,确保能获取到主构造函数。
  2. 有序属性获取:通过primaryConstructor.parameters拿到按定义顺序排列的参数,再映射为对应的成员属性。
  3. 高效字符串拼接:用StringBuilder替代直接字符串拼接,提升性能。
  4. 顺序填充数据:按属性定义顺序依次填充表头和每行数据,保证输出顺序和数据类一致。

测试示例

调用函数:

Log.d("AAA", datatableToStrings(listOf(Table1(0, "A", "H", "B"))))

带表头的输出结果:

id;dataA;dataH;dataB;
0;A;H;B;

如果不需要表头,删除bufferList[0].append("${prop.name};")这一行,就能得到纯数据行:

0;A;H;B;

内容的提问来源于stack exchange,提问作者rescuemod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 18:57:47