合并Kotlin中的两个数据类,它们具有对象列表并且可以为空

iecba09b  于 2023-02-13  发布在  Kotlin
关注(0)|答案(2)|浏览(149)

我在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(list1=[SomeObject1(id=1, info=Hello from someobject1 at 0), SomeObject1(id=2, info=Hello from someobject1.1 at 0)], list2=null, list3=null), exampleClass(list1=null, list2=[SomeObject2(id=2, info=Hello from someobject2 at 1), SomeObject2(id=3, info=Hello from someobject2.1 at 1)], list3=[SomeObject3(id=4, info=Hello from someobect3 at 1)]), exampleClass(list1=[SomeObject1(id=5, info=Hello from some object1 at 2), SomeObject1(id=6, info=Hello from someobject1 at 2.1)], list2=null, list3=null)]

我想把这3个exampleClass数组合并到一个exampleClass对象中,在这个对象中列表也应该合并。(如果列表的两个对象都不为空)

exampleClass(list1=[SomeObject1(id=1, info=Hello from someobject1 at 0), SomeObject1(id=2, info=Hello from someobject1.1 at 0), SomeObject1(id=5, info=Hello from some object1 at 2), SomeObject1(id=6, info=Hello from someobject1 at 2.1)], list2=[SomeObject2(id=2, info=Hello from someobject2 at 1), SomeObject2(id=3, info=Hello from someobject2.1 at 1)], list3=[SomeObject3(id=4, info=Hello from someobect3 at 1)])

这里,来自索引0的列表1与索引2合并。
我试过这个代码片段:

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)
}

我这样做是为了合并:

var finalExampleClass = exampleList.removeAt(0)
exampleList.map(
 finalExampleClass = finalExampleClass.merge(it)
)

但这只会在一个对象的list值为null而另一个对象的list值不为null的情况下才合并。

exampleClass(SomeObject1(id=5, info=Hello from some object1 at 2), SomeObject1(id=6, info=Hello from someobject1 at 2.1)], list2=[SomeObject2(id=2, info=Hello from someobject2 at 1), SomeObject2(id=3, info=Hello from someobject2.1 at 1)], list3=[SomeObject3(id=4, info=Hello from someobect3 at 1)])

在这个例子中,index0的list1被index2替换了,但是我想合并列表而不是替换它们,如果其中一个列表为null,那么合并就可以正常工作,就像我们看到的list2和list3一样。
有什么解决办法吗?

au9on6nz

au9on6nz1#

你可以使用Kotlin reduce函数来合并所有的ExampleClass示例,在这个reduce函数中,你需要把当前ExampleClass的元素添加到"累加"的示例中。
下面是一个例子:

val exampleClasses = listOf(ExampleClass(list1=listOf(SomeObject1(id="1", info="Hello from someobject1 at 0"), SomeObject1(id="2", info="Hello from someobject1.1 at 0")), list2=null, list3=null), ExampleClass(list1=null, list2=listOf(SomeObject2(id="2", info="Hello from someobject2 at 1"), SomeObject2(id="3", info="Hello from someobject2.1 at 1")), list3=listOf(SomeObject3(id="4", info="Hello from someobect3 at 1"))), ExampleClass(list1=listOf(SomeObject1(id="5", info="Hello from some object1 at 2"), SomeObject1(id="6", info="Hello from someobject1 at 2.1")), list2=null, list3=null))

val newExampleClass = exampleClasses.reduce { acc, current ->
    acc.copy(
        list1 = acc.list1.orEmpty().plus(current.list1 ?: emptyList()),
        list2 = acc.list2.orEmpty().plus(current.list2 ?: emptyList()),
        list3 = acc.list3.orEmpty().plus(current.list3 ?: emptyList()),
   )
}

当您看到newExampleClass的内容时,您会看到以下内容:

List1: [SomeObject1(id=1, info=Hello from someobject1 at 0), SomeObject1(id=2, info=Hello from someobject1.1 at 0), SomeObject1(id=5, info=Hello from some object1 at 2), SomeObject1(id=6, info=Hello from someobject1 at 2.1)]
List2: [SomeObject2(id=2, info=Hello from someobject2 at 1), SomeObject2(id=3, info=Hello from someobject2.1 at 1)]
List3: [SomeObject3(id=4, info=Hello from someobect3 at 1)]

此解决方案的唯一"问题"是,如果您希望在合并的ExampleClass示例中使用null值而不是空列表。
如果是这种情况,那么您可以使用let重新构建ExampleClass示例:

.let {
    it.copy(
        list1 = if (it.list1!!.isEmpty()) null else it.list1,
        list2 = if (it.list2!!.isEmpty()) null else it.list2,
        list3 = if (it.list3!!.isEmpty()) null else it.list3,
    )
}

注意:尽量使用val而不是var,以保证示例的属性不会及时改变。使用这个解决方案,你可以在ExampleClass中使用val,也可以在Object中使用val:

data class SomeObject1(
    val id: String,
    val info: String,
)

data class SomeObject2(
    val id: String,
    val info: String,
)

data class SomeObject3(
    val id: String,
    val info: String,
)

data class ExampleClass(
    val list1: List<SomeObject1>?,
    val list2: List<SomeObject2>?,
    val list3: List<SomeObject3>?
)
2w3kk1z5

2w3kk1z52#

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,
)

data class ExampleClass(
  var list1: List<SomeObject1>?,
  var list2: List<SomeObject2>?,
  var list3: List<SomeObject3>?,
)

val input = listOf(
  ExampleClass(
    list1 = listOf(
      SomeObject1("a", "0.1.0"),
      SomeObject1("b", "0.1.1")
    ),
    list2 = null,
    list3 = null
  ),
  ExampleClass(
    list1 = null,
    list2 = listOf(
      SomeObject2("c", "1.2.0"),
      SomeObject2("d", "1.2.1")),
    list3 = listOf(
      SomeObject3("e", "1.3.0")
    )
  ),
  ExampleClass(
    list1 = listOf(
      SomeObject1("f", "2.1.0"),
      SomeObject1("g", "2.1.1")
    ),
    list2 = null,
    list3 = null
  )
)

第一版:

val result = ExampleClass(
  list1 = input.filterNot { it.list1 == null }.flatMap { it.list1!! }.ifEmpty { null },
  list2 = input.filterNot { it.list2 == null }.flatMap { it.list2!! }.ifEmpty { null },
  list3 = input.filterNot { it.list3 == null }.flatMap { it.list3!! }.ifEmpty { null },
)

较短版本:

val result1 = ExampleClass(
  list1 = input.flatMap { it.list1 ?: emptyList() }.ifEmpty { null },
  list2 = input.flatMap { it.list2 ?: emptyList() }.ifEmpty { null },
  list3 = input.flatMap { it.list3 ?: emptyList() }.ifEmpty { null },
)

相关问题