skip to content

Explain the differences between `associate`, `associateBy`, and `associateWith`, including how each handles duplicate keys.

level: middleimportance: must knowfreq 75%

answer

  1. associateWith: element is the KEY
  2. associateBy: element is the VALUE
  3. associate: you return a Pair (both sides)
  4. Duplicate key = last-write-wins (silent loss)
  5. Need all collisions? use groupBy

basics

~20 s

All three build a map from a list. associateWith uses elements as keys, associateBy makes elements the values under a chosen key, and associate lets you build both key and value. If two keys collide, the last one wins.

solid answer

~30 s

These three create a `Map` where each element maps to exactly one value (unlike `groupBy`). `associate { it.id to it.name }` returns `Map<K, V>` from a `Pair` you produce. `associateBy(keySelector)` returns `Map<K, T>` — the key is derived, the value is the element; `associateBy(keySelector, valueTransform)` returns `Map<K, V>`. `associateWith(valueSelector)` returns `Map<T, V>` — the **element** is the key and you compute the value. Crucially, on a key collision the **last** element processed overwrites earlier ones (last-write-wins), so duplicate keys silently drop data — use `groupBy` when you must keep them all. The backing structure is a `LinkedHashMap`, preserving insertion order.

code

kotlin · 6 lines
kotlin
data class User(val id: Int, val name: String)
val users = listOf(User(1, "Ann"), User(2, "Bo"))

users.associateBy { it.id }            // {1=User(1,Ann), 2=User(2,Bo)}
users.associateWith { it.name.length } // {User(1,Ann)=3, User(2,Bo)=2}
users.associate { it.id to it.name }   // {1=Ann, 2=Bo}

go deeper

for a junior

Can name that all three produce a Map and pick associateBy to index a list by an id.

for a middle

Clearly distinguishes which side is the key for each, and knows duplicate keys are last-write-wins.

for a senior

Discusses Pair-allocation cost of associate vs the specialized variants and when to fall back to groupBy.

for a principal

Weighs API ergonomics, data-loss risk on collisions, and chooses defensively for untrusted/non-unique keys, e.g. validating uniqueness or using groupBy.

## The associate family All three turn an `Iterable`/`Sequence`/`Array` into a `Map<K, V>` where **each key holds a single value** (in contrast to `groupBy`, whose values are lists). ## `associate` `associate(transform: (T) -> Pair<K, V>): Map<K, V>` — the most general. You return a `Pair` for every element. ```kotlin val m = users.associate { it.id to it.email } // Map<Int, String> ``` Downside: it allocates a `Pair` per element. If only the key **or** only the value is derived from the element, prefer the more specific functions below, which skip the `Pair` allocation. ## `associateBy` The element becomes the **value**; you supply the **key**. - `associateBy(keySelector: (T) -> K): Map<K, T>` - `associateBy(keySelector, valueTransform): Map<K, V>` ```kotlin val byId = users.associateBy { it.id } // Map<Int, User> ``` ## `associateWith` The element becomes the **key**; you supply the **value**. - `associateWith(valueSelector: (T) -> V): Map<T, V>` ```kotlin val lengths = words.associateWith { it.length } // Map<String, Int> ``` ## Duplicate keys = last-write-wins If two elements yield the same key, the **later** element overwrites the earlier — earlier data is silently lost: ```kotlin listOf("ab", "cd", "ef").associateBy { it.length } // {2=ef} — "ab" and "cd" were overwritten ``` When you must retain every colliding element, use `groupBy` (which yields a `List` per key) instead. ## Order & backing All are eager and backed by `LinkedHashMap`, so iteration order matches the source's processing order. ## Quick mnemonic - **associateWith** → element **with** a computed value (element is the key). - **associateBy** → indexed **by** a computed key (element is the value). - **associate** → you build **both** sides via a Pair.

  • You have a list of products and want to retain ALL products that share a category. Which function?
    groupBy { it.category } — it returns Map<Category, List<Product>>. The associate family would drop all but the last product per category.
  • Why prefer associateBy over associate when only the key is derived?
    associateBy avoids allocating a Pair per element; it stores the element directly as the value, which is cheaper.

saying these in an interview costs you the question

  • Saying duplicate keys throw or keep all values (they silently overwrite, last wins)
  • Mixing up associateBy and associateWith (which side is the key)
  • Claiming associate returns Map<K, List<V>> like groupBy
  • Not knowing associate allocates a Pair per element

context