Search code examples
androidkotlinforeachdeclarative

How to copy a property between 2 lists of different types using declarative Kotlin?


Context

Using a declarative approach in Kotlin, need to copy a single name property from List of User objects to a List of UserDetail objects based on matching id properties as shown below:

val users = Arrays.asList(
        User(1, "a"),
        User(2, "b")
)
val details = Arrays.asList(
        UserDetail(1),
        UserDetail(2)
)
val detailsWithName = copyNameToUser(users, details)

Models are:

class User {
    var id = -1;
    var name = "" // given for all Users
    constructor(id: Int, name: String)
    // ...
}
class UserDetail {
    var id = -1;
    var name = "" // blank for all UserDetails
    constructor(id: Int)
    // ...
}

Problem

Tried to use a declarative approach via forEach iterable function:

fun copyNameToDetails(users: List<User>, details: List<UserDetail>): List<UserDetail> {
    details.forEach(d ->
        users.forEach(u ->
            if (d.id == u.id) {
                d.name = u.name
            }
        )
    )
    return details
}

This can be achieved in Java as shown below:

private static List<UserDetail> copyNameToDetails(List<User> users, List<UserDetail> details)   {
    for (UserDetail d: details) {
        for (User u : users) {
            if (d.id == u.id) {
                d.name = u.name;
            }
        }
    }
    return details;
}

Question

How can this be done in Kotlin using a declarative approach?


Solution

  • You make too many iterations over both lists (users.size * details.size) so creating a hashmap can fix it a bit:

    fun copyNameToUsers(users: List<User>, details: List<UserDetail>): List<UserDetail> {
        val usersById = users.associate { it.id to it }
        details.forEach { d ->
            usersById[d.id]?.let { d.name = it.name }
        }
    
        return details
    }