I am trying to reverse a Map in Kotlin. So far, I have come up with:
mapOf("foo" to 42)
.toList()
.map { (k, v) -> v to k }
.toMap()
Is there any better way of doing this without using a middleman(middlelist)?
v to k } .toMap() Is there any bett" /> v to k } .toMap() Is there any bett" /> v to k } .toMap() Is there any bett"/>
I am trying to reverse a Map in Kotlin. So far, I have come up with:
mapOf("foo" to 42)
.toList()
.map { (k, v) -> v to k }
.toMap()
Is there any better way of doing this without using a middleman(middlelist)?
On
Here is a simple extension function that reverse a map - without generating unneeded garbage (like pairs, intermediate data structures and unnecessary closures )
fun <K, V> Map<K, V>.reversed() = HashMap<V, K>().also { newMap ->
entries.forEach { newMap.put(it.value, it.key) }
}
note that apply is inlined, and entries.forEach is also inlined (which is not the same for Map::forEach)
On
I'm still learning the ins and outs of Kotlin, but I had the same requirement and as of Kotlin 1.2 it appears that you can iterate over a Map and so map() it directly like this:
@Test
fun testThatReverseIsInverseOfMap() {
val intMap = mapOf(1 to "one", 2 to "two", 3 to "three")
val revMap = intMap.map{(k,v) -> v to k}.toMap()
assertTrue(intMap.keys.toTypedArray() contentEquals revMap.values.toTypedArray())
assertTrue(intMap.values.toTypedArray() contentEquals revMap.keys.toTypedArray())
}
On
In case your map is not a 1-1 mapping and you want the inversion to be a list of values:
mapOf(1 to "AAA", 2 to "BBB", 3 to "BBB").toList()
.groupBy { pair -> pair.second } // Pair<Int, String>
.mapValues { entry ->
entry.value.map { it.first } // Entry<String, List<Pair<Int, String>>
}
On
If you need to reverse a multimap like m: Map<K, List<V>> to a Map<V, List<K>> you can do
m
.flatMap { it.value.map { oneValue -> oneValue to it.key } }
.groupBy({ it.first }, { it.second })
.toMap()
In sequence,
mapOf('a' to listOf('b', 'c'), 'd' to listOf('b'))
gets flat mapped to a sequence likelistOf('b' to 'a', 'c' to 'a', 'b' to 'd') which gets grouped tolistOf('b' to listOf('a', 'd'), 'c' to listOf('a')) which then gets converted to a map.This probably creates intermediate objects.
Since the
Mapconsists ofEntrys and it is notIterableyou can use Map#entries instead. It will be mapped to Map#entrySet to create a backed view ofSet<Entry>, for example:OR use Iterable#associate, which will create additional
Pairs.OR using Map#forEach: