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

如何合并Kotlin中含可空对象列表的数据类实例

问题:合并包含可空列表的数据类实例

我在Kotlin中定义了如下包含可空对象列表的数据类:

data class exampleClass(
    var list1: List<SomeObject1>?,
    var list2: List<SomeObject2>?,
    var list3: List<SomeObject3>?
)
data class SomeObject1(
    var id: String,
    var info: String,
)
data class SomeObject2(
    var id: String,
    var info: String,
)
data class SomeObject3(
    var id: String,
    var info: String,
)

现有一组exampleClass对象列表,希望将它们合并为一个exampleClass实例,其中各对应列表需进行合并(若两个实例的对应列表均非空)。例如三个exampleClass实例合并后,list1需包含所有实例中list1的元素,list2、list3同理。

我尝试了如下merge扩展函数:

inline fun <reified T : Any> T.merge(other: T): T {
    val nameToProperty = T::class.declaredMemberProperties.associateBy { it.name }
    val primaryConstructor = T::class.primaryConstructor!!
    val args = primaryConstructor.parameters.associateWith { parameter ->
        val property = nameToProperty[parameter.name]!!
        (property.get(other) ?: property.get(this))
    }
    return primaryConstructor.callBy(args)
}

但该函数仅在其中一个列表为null时生效,若两个列表均非空会直接替换而非合并,导致list1的原有元素被后续实例的list1覆盖。请问如何实现正确的合并逻辑?


解决方案

你需要修改扩展函数,针对可空List类型的属性做特殊合并逻辑:当两个实例的对应列表都非空时,拼接它们的元素;如果其中一个为null,取非空的那个;都为null则保持null。非List类型的属性可以保留原逻辑(优先取另一个实例的值,null则取当前实例的)。

修改后的扩展函数如下:

inline fun <reified T : Any> T.merge(other: T): T {
    val nameToProperty = T::class.declaredMemberProperties.associateBy { it.name }
    val primaryConstructor = T::class.primaryConstructor!!
    
    val args = primaryConstructor.parameters.associateWith { parameter ->
        val property = nameToProperty[parameter.name]!!
        val thisValue = property.get(this)
        val otherValue = property.get(other)
        
        // 处理可空List的合并
        if (property.returnType.isSubtypeOf(List::class.starProjectedType)) {
            when {
                thisValue == null && otherValue == null -> null
                thisValue == null -> otherValue
                otherValue == null -> thisValue
                else -> (thisValue as List<*>) + (otherValue as List<*>)
            }
        } else {
            // 非List类型:优先用other的值,null则用当前实例的
            otherValue ?: thisValue
        }
    }
    
    return primaryConstructor.callBy(args)
}

合并列表的使用示例

用fold函数遍历累积合并结果:

// 示例数据
val exampleList = listOf(
    exampleClass(listOf(SomeObject1("1", "info1")), null, null),
    exampleClass(null, listOf(SomeObject2("2", "info2")), null),
    exampleClass(listOf(SomeObject1("3", "info3")), listOf(SomeObject2("4", "info4")), listOf(SomeObject3("5", "info5")))
)

// 合并所有实例
val mergedResult = exampleList.fold(exampleClass(null, null, null)) { acc, item -> acc.merge(item) }

补充说明

  • 函数通过Kotlin反射识别List类型属性,确保只有列表会执行合并逻辑,其他类型保持原有替换规则。
  • 如果你的数据类中有其他需要自定义合并逻辑的类型,可以在函数中新增对应的判断分支。
  • 建议遵循Kotlin命名规范,将类名改为大驼峰形式(比如ExampleClass),提升代码可读性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 05:05:19