Reputation: 1799
I have two lists. One is called oldList
and contains old data, the 2nd one is called updateList
and contains a set of updates.
I want to create a new list with those rules:
oldList
id
id
of an updated item already exists in oldData
, replace itI came up with a simple code:
Item.kt
data class Item (val id: String, val text: String)
Main.kt
fun main() {
val oldList: List<Item> = listOf(
Item("aaa1", "aaa2"),
Item("bbb1", "bbb2"),
Item("ddd1", "ddd2"))
val updateList: List<Item> = listOf(
Item("aaa1", "aaa3"),
Item("ccc1", "ccc2"))
val resultList = oldList.toMutableList()
for (item in updateList) {
val index = oldList.indexOfFirst { it.id == item.id }
if (index < 0) {
resultList.add(item)
} else {
resultList[index] = item
}
}
println(resultList)
}
This works fine but I can imagine it's inefficient and there might also be some nice Kotlin
idiom. Is there a better solution?
Upvotes: 9
Views: 8412
Reputation: 93551
If the original order doesn't matter, you can combine the lists, putting the new values first to favor them in a distinctBy
call:
val resultList = (updateList + oldList).distinctBy(Item::id)
If the order matters exactly as you described it, you can convert both lists to maps before combining them. When combining two Maps with +
, the items in the second Map take precedence, but the order from the first Map is preserved.
val resultList =
(oldList.associateBy(Item::id) + updateList.associateBy(Item::id)).values.toList()
Upvotes: 12
Reputation: 3232
You can use the distinctBy
method:
val resultList = (updateList + oldList).distinctBy { it.id }
What distinctBy
does is return a new list containing only elements having distinct keys returned by the provided lambda. You must bear in mind however that the order of elements matters and the first encountered item with the given key is kept in the result list, the others are ignored.
Upvotes: 2
Reputation: 2083
If you override equals and hashcode to use only id, as it seems to be the right thing to do as if your class uses an id I'm not sure if it is data class
data class Item(val id: String,
val text: String) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as Item
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
return id.hashCode()
}
}
then you can just make an union of the updateList with the old one
fun main() {
val oldList: List<Item> = listOf(
Item("aaa1", "aaa2"),
Item("bbb1", "bbb2"),
Item("ddd1", "ddd2"))
val updateList: List<Item> = listOf(
Item("aaa1", "aaa3"),
Item("ccc1", "ccc2"))
val resultList = updateList.union(oldList)
println(resultList)
}
Upvotes: 1