1. Overview
Map is a commonly used data structure in Kotlin for manipulating key-value associations.
In this quick tutorial, let’s explore how to convert a Map to Lists in Kotlin.
2. Introduction to the Problem
A Map carries key-value associations. When we talk about converting a Map to Lists, there could be two cases:
- Converting to one list – The elements in this list represent the original key-value associations.
- Converting to two lists – A list of keys and a list of values
Moreover, considering the “two lists” case carefully, we can cover another two scenarios. The simplest scenario involves obtaining separate key and value lists without preserving their original key-value associations within the map.
However, sometimes, we want the converted key list and the value list to be correlated. In other words, given an index i, the elements keyList[i] and valueList[i] are still associated as they were in the original map:
Map:
k1 -> v1
k2 -> v2
k3 -> v3
index : 0, 1, 2
keyList : k1, k2, k3
valueList: v1, v2, v3
We’ll discuss converting a map to lists, covering all the scenarios mentioned above.
So first, let’s create a Kotlin Map object as the input example:
val DEV_MAP: Map<String, String> = mapOf(
"Kent" to "Linux",
"Eric" to "MacOS",
"Kevin" to "Windows",
"Michal" to "MacOS",
"Saajan" to "Linux",
)
As the code above shows, we initialized a Map using the mapOf() function. The map stores five developers and the primary operating systems they use.
Next, we’ll convert this DEV_MAP to lists. Additionally, to ensure clarity and verification, we’ll use unit test assertions to verify whether each approach produces the expected result.
3. Converting to One List
First, let’s convert DEV_MAP to one list.
3.1. Getting a List of Map.Entry
In Kotlin, map.entries gives us a read-only Set of all entries in the map. Then, we can use toList() to convert the set to a list:
val result = DEV_MAP.entries.toList()
assertEquals(DEV_MAP.size, result.size)
result.forEach { entry ->
assertEquals(DEV_MAP[entry.key], entry.value)
}
3.2. Getting a List of Key-Value Pairs
Alternatively, the map.toList() function returns a list of key-value Pairs. Therefore, we can get List<Pair<String, String>> by simply calling DEV_MAP.toList():
val result = DEV_MAP.toList()
assertEquals(DEV_MAP.size, result.size)
result.forEach { pair ->
assertEquals(DEV_MAP[pair.first], pair.second)
}
4. Converting to a List of Keys and a List of Values
In this section, let’s delve into converting a map into separate key and value lists. Additionally, we’ll explore techniques for maintaining the relationship between these key and value lists intact.
4.1. No Correlation Between Key and Value Lists
It would be a simple task if we merely aimed to obtain key and value lists from a map without concern for retaining the initial key-value pair associations. This is because Kotlin’s Map provides the keys and values properties, which return a Set of keys and a Collection of values, respectively. What we need to do is convert them to lists using the handy toList() function:
val keyList = DEV_MAP.keys.toList()
val valueList = DEV_MAP.values.toList()
assertThat(keyList).containsExactlyInAnyOrder("Kent", "Eric", "Kevin", "Michal", "Saajan")
assertThat(valueList).containsExactlyInAnyOrder("Linux", "MacOS", "Windows", "MacOS", "Linux")
4.2. Getting Correlated Key and Value Lists
The first idea that comes up to get correlated key and value lists might be iterating through the map entries and filling each entry’s key and value in two pre-initialized key and value lists:
val keyList = mutableListOf<String>()
val valueList = mutableListOf<String>()
DEV_MAP.entries.forEach {
keyList += it.key
valueList += it.value
}
assertThat(keyList).hasSize(DEV_MAP.size)
assertThat(valueList).hasSize(DEV_MAP.size)
//verify correlation
repeat(DEV_MAP.size) { idx -> assertEquals(DEV_MAP[keyList[idx]], valueList[idx]) }
In the code above, it’s worth noting that *we used the MutableList‘s plusAssign operator (+=) to add an element to the list.*
Alternatively, we can transform the map into a Pair of correlated keyList and valueList. This approach doesn’t require pre-initializing the two lists:
val (keyList, valueList) = DEV_MAP.toList().let { kvpList -> kvpList.map { it.first } to kvpList.map { it.second } }
assertThat(keyList).hasSize(DEV_MAP.size)
assertThat(valueList).hasSize(DEV_MAP.size)
repeat(DEV_MAP.size) { idx -> assertEquals(DEV_MAP[keyList[idx]], valueList[idx]) }
Next, let’s understand how this one-liner works.
We’ve learned that DEV_MAP.toList() returns a list of key and value pairs. The let{} function transformed List<Pair<key, value>> into Pair<keyList, valueList>. Then, we used Kotlin’s deconstructing declaration to assign the two lists in the pair to two list variables.
5. Conclusion
In this article, we initially discussed different problem scenarios involving the conversion of a map into lists. Then, we explored how to solve the problem in each scenario through examples.
As always, the complete source code for the examples is available over on GitHub.