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.