Joffrey
12/19/2019, 10:24 AMfun List<Pair<K,V>>.toMap()
drops duplicate entries without providing a way to merge them. Is there a stdlib function that can do this?
I often need this when dealing with maps containing quantities. I implement it this way:
fun <K, V> List<Pair<K, V>>.toMap(combine: (V, V) -> V?): Map<K, V> {
val result = mutableMapOf<K, V>()
for ((k, v) in this) {
result.merge(k, v, combine)
}
return result
}
Another one I'm missing is merging 2 maps provided a function to recombine the values of keys that are present in both maps.Michael de Kaste
12/19/2019, 10:28 AMJoffrey
12/19/2019, 10:35 AMgroupBy
only groups values in lists, it doesn't reduce
these lists, so it is still quite cumbersome to use it:
fun <K, V> List<Pair<K, V>>.toMap(combine: (V, V) -> V): Map<K, V> =
groupBy({ it.first }, { it.second})
.mapValues { it.value.reduce { v1, v2 -> combine(v1, v2) } }
Or am I missing something here?Michael de Kaste
12/19/2019, 10:42 AMMichael de Kaste
12/19/2019, 10:42 AMMichael de Kaste
12/19/2019, 10:46 AMJoffrey
12/19/2019, 10:49 AMtoMap()
to actually allow the users to avoid reimplementing a mix of groupBy
+ reduce
for such a common use case.
The critical point here is: is that a really common use case, or am I the only one who needs to merge things? Also, seeing this overload in the autocomplete would probably make the users think of "Oh yeah, what if there are duplicates?"Michael de Kaste
12/19/2019, 10:50 AMMichael de Kaste
12/19/2019, 10:51 AMmap.groupingBy { it.first }.fold(null) { accumulator: Int?, element -> merge(element.second, accumulator) }
I would do it like this if you have no default value for your merging strategy (or 0 if that's fine too)Joffrey
12/19/2019, 10:53 AMJoffrey
12/19/2019, 11:00 AMInt
here. I'd rather implement the utility function from my original post, which also needs to allocate way less objects in the end.Michael de Kaste
12/19/2019, 11:02 AMJoffrey
12/19/2019, 11:07 AMgroupingBy
still creates an intermediate Grouping
instance, but I have to admit it's already better. Anyway, I can also express the initial function directly with the following:
fun <K, V> List<Pair<K, V>>.toMap(combine: (V, V) -> V?): Map<K, V> =
fold(mutableMapOf<K, V>()) { m, p -> m.merge(p.first, p.second, combine); m }
Using fold
directly solves the problem of intermediate stuff, but it's still a bit overkill, because reading that is not very nice to my eye 🙂Michael de Kaste
12/19/2019, 11:09 AMJoffrey
12/19/2019, 11:11 AMMike
12/19/2019, 12:16 PMJoffrey
12/19/2019, 1:04 PM