Dictionary 获取kotlin中两个贴图之间的差异

Dictionary 获取kotlin中两个贴图之间的差异,dictionary,kotlin,Dictionary,Kotlin,我试图检测科特林两张地图之间的差异 我设置了以下示例,以便更容易地解释我试图实现的目标: fun main() = runBlocking { val firstMapOfAnimals = mapOf( Pair("key1", Dog(name = "Dog aaa")), Pair("key2", Dog(name = "Dog bbb", breed = "

我试图检测科特林两张地图之间的差异

我设置了以下示例,以便更容易地解释我试图实现的目标:

fun main() = runBlocking {

    val firstMapOfAnimals = mapOf(
        Pair("key1", Dog(name = "Dog aaa")),
        Pair("key2", Dog(name = "Dog bbb", breed = "Bulldog")),
        Pair("key4", Cat(name = "Cat ddd", color = "White")),
        Pair("key5", Cat(name = "Cat eee", color = "Blue")),
        Pair("key6", Cat(name = "Cat fff", color = "Blue"))
    )

    val secondMapOfAnimals = mapOf(
        Pair("key2", Dog(name = "Dog BBB")),
        Pair("key3", Dog(name = "Dog CCC")),
        Pair("key4", Cat(name = "Cat DDD", color = "Grey")),
        Pair("key6", Dog(name = "Dog FFF", breed = "Husky"))
    )

    val diffResult = diff(firstMapOfAnimals, secondMapOfAnimals)

    val expectedResultMap = mapOf(
        Pair("key2", Dog(name = "Dog BBB", breed = "Bulldog")),
        Pair("key3", Dog(name = "Dog CCC")),
        Pair("key4", Cat(name = "Cat DDD", color = "Grey")),
        Pair("key6", Dog(name = "Dog FFF", breed = "Husky"))
    )

    println("Actual: $diffResult")
    println("Expected: $expectedResultMap")

}

private fun diff(
    firstMap: Map<String, Animal>,
    secondMap: Map<String, Animal>
): Map<String, Animal> {
    val result = mapOf<String, Animal>()
    //TODO: get differences between firstMap and secondMap
    return result
}

abstract class Animal

data class Dog(
    val name: String,
    val breed: String = "breed"
) : Animal()

data class Cat(
    val name: String,
    val color: String = "black"
) : Animal()
我相信这可以通过多种操作符的组合来解决,但由于我对kotlin的知识仍然有限,我不确定如何实现这一点


有人能给我指个方向吗?

您可以使用现有的
减号()
运算符扩展函数:

secondMapOfAnimals.minus(firstMapOfAnimals)
或者更简洁地说:

secondMapOfAnimals - firstMapOfAnimals
另请注意,您可以使用
to()
infix扩展函数创建对:

"key1" to Dog(name = "Dog aaa")
而不是

Pair("key1", Dog(name = "Dog aaa"))

您可以使用现有的
减号()
运算符扩展函数:

secondMapOfAnimals.minus(firstMapOfAnimals)
或者更简洁地说:

secondMapOfAnimals - firstMapOfAnimals
另请注意,您可以使用
to()
infix扩展函数创建对:

"key1" to Dog(name = "Dog aaa")
而不是

Pair("key1", Dog(name = "Dog aaa"))

你想要相当具体的区别。 将根据提供的示例尝试将其正式化:

  • 如果键在第一个映射中存在,但在第二个映射中不存在,则该键将被丢弃
  • 如果键出现在第二个映射中,但不在第一个映射中,则会保留该键
  • 如果键在两个映射中都存在,并且值相等,则将放弃该键
  • 如果两个映射中都存在键,但值的类型不同,则第二个映射中的值优先
  • 如果键在两个映射中都存在,并且值的类型相同,则生成的diff值应包含不同的属性
    • 属性的非默认值应优先
    • 如果两个属性的值均为非默认值,则第二个属性的值优先((?),即使两者相等)
  • 前4个步骤可以这样做:

    secondMap.map{(键,secondValue)->
    val firstValue=firstMap[键]?:return@map第二个值的键
    if(firstValue==secondValue)return@mapnull//稍后将过滤掉它们
    如果(firstValue.javaClass!=secondValue.javaClass)键指向secondValue
    animalDiff的else键(第一个值,第二个值)
    }.filterNotNull().toMap()
    
    但是第五步(嵌入
    animalDiff
    函数)相当棘手。问题是,在Kotlin中,甚至通过反射(因为它可能不仅仅是编译时常量,而是任意表达式,包括函数调用)

    您可以执行以下操作:为
    Animal
    类的所有子类的所有属性添加默认值,以便通过;之后,可以从此虚拟实例确定默认值

    数据类狗(
    val name:String=“”,
    val-breed:String=“breed”
    ):动物()
    数据类Cat(
    val name:String=“”,
    val color:String=“黑色”
    ):动物()
    私人娱乐动物论坛(第一:T,第二:T):T{
    val clazz:KClass=first::class作为KClass
    val dummyInstance=clazz.createInstance()
    val构造函数=clazz.primaryConstructor!!
    val constructorArgs=clazz.memberProperties.associate{prop:KProperty1->
    val defaultValue=prop.get(dummyInstance)
    val firstPropValue=prop.get(第一个)
    val secondPropValue=prop.get(秒)
    val resultPropValue=when{
    //secondPropValue==firstPropValue->defaultValue//uncomment,如果它对您的差异逻辑有意义的话
    secondPropValue!=默认值->secondPropValue
    firstPropValue!=defaultValue->firstPropValue
    else->defaultValue
    }
    //需要将KProperty转换为KParameter以将其传递给构造函数
    //对于数据类来说应该可以很好地工作
    val constructorParam=constructor.parameters.find{it.name==prop.name}!!
    return@associateconstructorParam到resultPropValue
    }
    返回constructor.callBy(constructorArgs)
    }
    
    您需要相当具体的差异。 将根据提供的示例尝试将其正式化:

  • 如果键在第一个映射中存在,但在第二个映射中不存在,则该键将被丢弃
  • 如果键出现在第二个映射中,但不在第一个映射中,则会保留该键
  • 如果键在两个映射中都存在,并且值相等,则将放弃该键
  • 如果两个映射中都存在键,但值的类型不同,则第二个映射中的值优先
  • 如果键在两个映射中都存在,并且值的类型相同,则生成的diff值应包含不同的属性
    • 属性的非默认值应优先
    • 如果两个属性的值均为非默认值,则第二个属性的值优先((?),即使两者相等)
  • 前4个步骤可以这样做:

    secondMap.map{(键,secondValue)->
    val firstValue=firstMap[键]?:return@map第二个值的键
    if(firstValue==secondValue)return@mapnull//稍后将过滤掉它们
    如果(firstValue.javaClass!=secondValue.javaClass)键指向secondValue
    animalDiff的else键(第一个值,第二个值)
    }.filterNotNull().toMap()
    
    但是第五步(嵌入
    animalDiff
    函数)相当棘手。问题是,在Kotlin中,甚至通过反射(因为它可能不仅仅是编译时常量,而是任意表达式,包括函数调用)

    您可以执行以下操作:为
    Animal
    类的所有子类的所有属性添加默认值,以便通过;之后,可以从此虚拟实例确定默认值

    数据类狗(
    val name:String=“”,
    val-breed:String=“breed”
    ):动物()
    数据类Cat(
    val name:String=“”,
    val color:String=“黑色”
    ):动物()
    私人娱乐动物论坛(第一:T,第二:T):T{
    val clazz:KClass=first::class作为KClass
    val dummyInstance=clazz.createInstance()
    val构造函数=clazz.primaryConstructor!!
    val constructorArgs=clazz.memberProperties.associate{prop:KProperty1->
    val defaultValue=prop.get(dummyInstance)
    val firstPropValue=prop.get(第一个)
    v