Android Kotlin Collection Processing
Beginner-to-advanced Kotlin collection reference for Android, covering mutability, transformations, filtering, grouping, aggregation, sequences, allocation, complexity, concurrency boundaries, and production patterns.
Collection Foundations
Core collection types and naming rules.
List, Set & Map
The main Kotlin collection shapes and their mutable variants.
| Type | Ordering | Duplicates | Lookup Model | Choose When |
|---|---|---|---|---|
| List<T> | Index-ordered | Allowed | By index; membership is generally linear | Order and repeated values matter |
| Set<T> | Implementation-dependent | Not allowed by equality | Membership is typically constant-time for hash sets | Uniqueness and membership checks dominate |
| Map<K, V> | Implementation-dependent | Keys unique; values may repeat | By key, typically constant-time for hash maps | Values have stable lookup keys |
| Sequence<T> | Source order | Allowed | Lazy pipeline, no indexed contract | A multi-step pipeline can avoid intermediate collections |
| MutableList / Set / Map | Matches implementation | Matches collection kind | In-place mutation | One clear owner needs controlled mutation |
List preserves order and duplicates; Set stores unique values; Map stores key-value pairs.
Read-only collections prevent mutation through that reference, but are not always deeply immutable.
Operator Naming Rules
Think in stages: transform → filter → select → group → aggregate.
Transformations
Convert elements into new values or collection shapes.
map, mapIndexed & mapNotNull
map returns one output element for every input element.
Use mapNotNull when failed conversions or missing values should be skipped.
flatMap & flatten
map transforms; flatMap transforms and flattens; flatten only removes one nesting level.
Filtering & Selection
Keep matching elements or safely retrieve values.
filter, filterNot & Type Filtering
filter checks the whole collection; takeWhile and dropWhile only inspect from the beginning.
take, drop, slice, chunked & windowed
Use chunked for batches; use windowed for moving comparisons or neighbouring values.
first, last, single, find & elementAt
first(), last(), and single() may throw. Use OrNull variants when absence is expected.
find(predicate) is equivalent to firstOrNull(predicate).
Checks, Distinctness & Ordering
any, all, none, contains & count
distinct, sorted & Comparator Chains
reversed() flips current order; sortedDescending() performs a descending sort.
Grouping & Association
associate, associateBy & associateWith
associateBySelector creates the key; the original item becomes the value.
associateWithOriginal item becomes the key; selector creates the value.
Duplicate keys overwrite earlier values in associateBy and associate.
groupBy, groupingBy & partition
groupBy builds lists immediately; groupingBy supports operations such as eachCount, fold, and reduce.
Combining & Aggregation
zip, unzip & Set Operations
zip stops when the shorter collection runs out of elements.
sum, sumOf, average, min & max
fold, reduce & Running Aggregates
reduce uses the first element as its accumulator and throws on an empty collection.
fold works with empty collections and can produce a different result type.
Lazy Processing & Patterns
Sequence Processing
Collections process each stage eagerly; Sequence moves one element through the full pipeline at a time.
Sequences help most with large inputs, long chains, or early termination—not every small collection.
Complete Processing Pipeline
productsBegin with the source collection.
.filter { it.available }Keep only relevant items.
.mapValuesShape the final result for its consumer.
Read collection chains top to bottom: source → filter → transform → order → group → result.
Common Mistakes & Quick Reference
Prefer clear chains of small operations over one large lambda with several responsibilities.
Mutability, Copying & Destinations
Control ownership and allocation when collections cross Android architecture boundaries.
Read-Only Is Not Deeply Immutable
Kotlin's List, Set, and Map interfaces prevent mutation through that reference, but the backing collection or contained objects may still mutate.
When a repository or ViewModel publishes state, copy or use a persistent immutable collection if another owner could still mutate the backing data.
toList copies the container, not mutable elements. Prefer immutable element models or explicitly deep-copy where the domain requires isolation.
+, -, += and Mutation
plus/minus return new collections. += mutates a mutable receiver when plusAssign exists, but reassigns a read-only var using plus otherwise.
Building a large List with result = result + item copies the growing list on every iteration. Use buildList, a mutable builder, or a destination operator.
mapTo, filterTo & Collection Builders
Destination variants reuse or select a result collection type; buildList/buildMap expose controlled mutation only inside the builder.
Use ordinary map/filter by default. Destination variants matter in measured hot paths, when appending to an existing result, or when the result type is semantically important.
Advanced Grouping, Indexing & Duplicates
Build indices and summaries without losing records accidentally.
Duplicate Key Policies
associateBy keeps the last value for a duplicate key. Choose reject, first, last, or group explicitly when duplicates carry meaning.
If uniqueness is a domain invariant, validate it. Do not let associateBy silently hide malformed server or database data.
groupingBy fold, reduce & aggregate
Grouping operations calculate per-key results without allocating a List for every group as groupBy does.
aggregate exposes key, current accumulator, element, and first-element status. Prefer fold/eachCount when they express the calculation more clearly.
Complexity, Concurrency & Android UI
Make performance and thread-safety choices based on actual collection size, access pattern, and ownership.
Complexity & Allocation Guide
Most transformations scan O(n) and allocate a result; sorting is O(n log n); repeated linear membership can turn a pipeline quadratic.
Replacing repeated List membership with a Set or prebuilt Map usually matters more than reducing a small lambda allocation. Profile realistic devices and data.
Thread Safety & Publication
Standard mutable collections are not thread-safe. Prefer single ownership and immutable snapshots across coroutine/thread boundaries.
Coroutines can run concurrently and resume on different threads. Use confinement, Mutex, actors, concurrent structures, or atomic immutable-state updates.
Collections as Android UI State
Publish immutable lists with stable item identity. Compute expensive projections outside rendering or memoize them against correct inputs.
Copy only changed immutable elements while reusing unchanged objects. Diffing and Compose skipping can then use stable identity/equality effectively.
Collection operators process in-memory elements; Flow operators process asynchronous emissions. See Android Kotlin Flows for cancellation, context, buffering, and sharing.
Production Checklist
Review semantics, ownership, absence, duplicates, allocation, complexity, and thread safety.