Kotlin List to Map Conversion: 5 Efficient Methods for Custom Objects
Kotlin provides inline extension functions—associate, associateBy, associateWith, and groupBy—that convert lists to maps in O(n) time with minimal allocations by leveraging stdlib implementations in libraries/stdlib/common/src/generated/_Collections.kt.
When working with the JetBrains/kotlin repository's standard library, developers frequently need to transform collections of custom objects into lookup maps for efficient access. The Kotlin stdlib offers specialized kotlin list to map conversion functions that eliminate boilerplate while maintaining optimal performance through inline compilation and direct use of LinkedHashMap implementations.
Core Extension Functions for List-to-Map Conversion
The Kotlin standard library defines four primary approaches in _Collections.kt that handle different mapping scenarios. Each function is declared as inline, allowing the compiler to eliminate lambda overhead and generate tight loops specialized for your specific types.
Using associate() for Custom Key-Value Pairs
The associate() function provides maximum flexibility by letting you return a Pair for each element, defining both key and value explicitly.
According to the source in libraries/stdlib/common/src/generated/_Collections.kt, the signature is:
inline fun <T, K, V> Iterable<T>.associate(transform: (T) -> Pair<K, V>): Map<K, V>
The implementation iterates once over the collection, invoking transform for each element and inserting results into a mutable LinkedHashMap. This preserves the original list order while running in linear time.
Using associateBy() for Key Selection
When your custom object should become the map value and you only need to extract the key, associateBy avoids the overhead of creating intermediate Pair objects.
The single-selector variant defined in the stdlib:
inline fun <T, K> Iterable<T>.associateBy(keySelector: (T) -> K): Map<K, T>
For scenarios requiring both key extraction and value transformation, use the two-parameter overload:
inline fun <T, K, V> Iterable<T>.associateBy(
keySelector: (T) -> K,
valueTransform: (T) -> V
): Map<K, V>
Using associateWith() for Value Derivation
If your custom object serves as the natural key and you need to compute derived values, use associateWith(). This maintains the element as the key while applying a transformation to generate values:
inline fun <T, V> Iterable<T>.associateWith(valueTransform: (T) -> V): Map<T, V>
Using groupBy() for Multi-Value Grouping
Unlike the other functions that store single values, groupBy collects all elements sharing the same key into List values, making it ideal for grouping operations:
inline fun <T, K> Iterable<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>>
This allocates both the outer LinkedHashMap and inner MutableList instances for each unique key.
Implementation Details and Performance Characteristics
All kotlin list to map conversion functions in the JetBrains repository share common implementation traits that optimize execution speed and memory usage.
Inline Compilation Benefits
Because these functions are marked inline, the Kotlin compiler emits the lambda body directly at the call site rather than invoking it as an anonymous class. This eliminates object allocation for the lambda itself and enables type specialization for primitive values, reducing boxing overhead.
LinkedHashMap and Order Preservation
The underlying implementations use LinkedHashMap rather than HashMap, ensuring that iteration order matches the original list sequence. This deterministic behavior is crucial when working with ordered collections of custom objects.
Source File Location
The actual implementations reside in libraries/stdlib/common/src/generated/_Collections.kt, which contains the generated inline code that the compiler expands during compilation. This file handles the collection-to-map transformation logic used across all Kotlin platforms.
Complete Code Examples with Custom Objects
Consider a custom data class representing users in a system:
data class Person(val id: Int, val name: String, val age: Int)
val people = listOf(
Person(1, "Alice", 30),
Person(2, "Bob", 25),
Person(3, "Charlie", 30)
)
Converting with associate()
Create a map from ID to name using the flexible pair constructor:
val idToName: Map<Int, String> = people.associate { it.id to it.name }
// Result: {1=Alice, 2=Bob, 3=Charlie}
Converting with associateBy()
Store the full object as the value using a single key selector:
val idToPerson: Map<Int, Person> = people.associateBy { it.id }
Or transform the value while selecting the key, handling duplicate keys (last wins) automatically:
val ageToName: Map<Int, String> = people.associateBy(
keySelector = { it.age },
valueTransform = { it.name }
)
// Result: {30=Charlie, 25=Bob} - Charlie overwrites Alice for key 30
Converting with associateWith()
Use the Person object as the key with computed values:
val personToAge: Map<Person, Int> = people.associateWith { it.age }
Converting with groupBy()
Group multiple persons by age, creating lists for duplicate keys:
val personsByAge: Map<Int, List<Person>> = people.groupBy { it.age }
// Result: {30=[Alice, Charlie], 25=[Bob]}
Performance Optimization Tips
When performing kotlin list to map conversion on large datasets, consider these strategies from the JetBrains stdlib implementation:
-
Prefer
associateByoverassociatewhen you only need the original element as the value. Theassociatefunction constructs an intermediatePairfor each element, whileassociateBywrites directly to the map, reducing allocation pressure. -
Use mutable maps only when necessary. If you need to add entries after conversion, call
.toMutableMap()on the result rather than using mutable operations during the initial transformation. The initial conversion remains O(n), and you avoid premature optimization complexity. -
Avoid
groupByfor presence checks. If you only need to verify whether a key exists rather than collecting all values, useassociateBywith a dummy constant value. ThegroupByfunction allocates aListfor every unique key, consuming significantly more memory than a simple map when you don't need the grouped collections.
Summary
- The Kotlin stdlib provides
associate,associateBy,associateWith, andgroupByas inline extension functions for kotlin list to map conversion, all defined inlibraries/stdlib/common/src/generated/_Collections.kt. - These functions operate in O(n) linear time, using
LinkedHashMapto preserve input order and minimize allocations. - The
inlinemodifier eliminates lambda overhead, allowing the compiler to generate optimized, type-specific code for custom objects. associateByoffers better performance thanassociatewhen you don't need custom value transformations, as it avoids intermediatePaircreation.- For grouping scenarios,
groupBycreatesListvalues for each key, while the other functions store single values and overwrite duplicates (last-write-wins).
Frequently Asked Questions
What is the difference between associate and associateBy in Kotlin list to map conversion?
The associate function requires a lambda that returns a Pair<K, V> for each element, giving you explicit control over both key and value generation but creating temporary Pair objects during processing. In contrast, associateBy takes a keySelector lambda and uses the original element as the value automatically, eliminating Pair allocation overhead and providing better performance when you don't need to transform the value.
How does Kotlin handle duplicate keys during list to map conversion?
All stdlib conversion functions use Map.put() semantics where duplicate keys are overwritten by subsequent entries, following a last-write-wins strategy. For associate, associateBy, and associateWith, the final element in the list determines the value for any duplicate key. Only groupBy preserves all elements by collecting them into a List mapped to each key.
Which function provides the best performance for converting a large list to a map?
For maximum performance with custom objects, use associateBy with a single key selector when the original element serves as the value, or associateWith when the element serves as the key. Both avoid the intermediate Pair allocation required by associate. The inline nature of these functions ensures the compiler generates specialized loops without boxing overhead for primitive properties.
Does Kotlin preserve list order when converting to a map?
Yes, all standard list-to-map conversion functions in libraries/stdlib/common/src/generated/_Collections.kt use LinkedHashMap as their underlying implementation, which maintains insertion order during iteration. This means the resulting map iterates in the same sequence as the original list, providing deterministic behavior essential for debugging and UI consistency.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →