Skip to content

Instantly share code, notes, and snippets.

@josdejong
Last active October 24, 2023 09:30
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save josdejong/fbb43ae33fcdd922040dac4ffc31aeaf to your computer and use it in GitHub Desktop.
Save josdejong/fbb43ae33fcdd922040dac4ffc31aeaf to your computer and use it in GitHub Desktop.
Merge two data classes in Kotlin
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.primaryConstructor
/**
* Merge two data classes
*
* The resulting data class will contain:
* - all fields of `other` which are non null
* - the fields of `this` for the fields which are null in `other`
*
* The function is immutable, the original data classes are not changed
* and a new data class instance is returned.
*
* Example usage:
*
* val a = MyDataClass(...)
* val b = MyDataClass(...)
* val c = a merge b
*/
infix 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)
}
@josdejong
Copy link
Author

Something like this - just change the exact logic to meet your needs (and think through what logic you need for Double, Float, Int. etc, there may be a smart way to check whether any numeric type is zero, I don't know):

    infix inline fun <reified T : Any> T.mergeIgnoreZero(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 valueOther = property.get(other)
            val valueThis = property.get(this)

            if (valueOther is Double && valueOther == 0.0) {
                valueThis
            } else {
                valueOther ?: valueThis
            }
        }
        return primaryConstructor.callBy(args)
    }

@talatkuyuk
Copy link

@josdejong Thank you very much. It worked.

@josdejong
Copy link
Author

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment