Collections
## Learning Objectives
- Understand list, set, and map interfaces
- Learn mutable vs immutable collections
- Work with collection functions
- Use sequences for lazy evaluation
## Collection Types Overview
| Type | Description | Immutable | Mutable |
|------|-------------|-----------|---------|
| List | Ordered collection | `listOf()` | `mutableListOf()` |
| Set | Unique elements | `setOf()` | `mutableSetOf()` |
| Map | Key-value pairs | `mapOf()` | `mutableMapOf()` |
## List
### Immutable List
```kotlin
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
println(numbers[0]) // 1
println(numbers.first()) // 1
println(numbers.last()) // 5
println(numbers.size) // 5
// Iteration
for (num in numbers) {
print("$num ")
}
println()
// Functional iteration
numbers.forEach { print("$it ") }
println()
}
```
### Mutable List
```kotlin
fun main() {
val numbers = mutableListOf(1, 2, 3)
numbers.add(4)
numbers.addAll(listOf(5, 6))
numbers[0] = 10
numbers.removeAt(1)
numbers.remove(6)
println(numbers) // [10, 3, 4, 5]
}
```
### List Operations
```kotlin
fun main() {
val list = listOf(1, 2, 3, 4, 5)
// Sublist
println(list.subList(1, 4)) // [2, 3, 4]
// Contains
println(3 in list) // true
println(list.contains(3)) // true
// Index of
println(list.indexOf(3)) // 2
println(list.lastIndexOf(3)) // 2
// Slice
println(list.slice(listOf(0, 2, 4))) // [1, 3, 5]
}
```
## Set
### Immutable Set
```kotlin
fun main() {
val fruits = setOf("apple", "banana", "apple", "cherry")
println(fruits) // [apple, banana, cherry]
println(fruits.size) // 3
println("banana" in fruits) // true
// First and last
println(fruits.first()) // apple
println(fruits.last()) // cherry
}
```
### Mutable Set
```kotlin
fun main() {
val set = mutableSetOf(1, 2, 3)
set.add(4)
set.addAll(listOf(5, 6))
set.remove(2)
set.add(2) // Adding again - no effect
println(set) // [1, 3, 4, 5, 6]
}
```
### Set Operations
```kotlin
fun main() {
val set1 = setOf(1, 2, 3, 4)
val set2 = setOf(3, 4, 5, 6)
println(set1 union set2) // [1, 2, 3, 4, 5, 6]
println(set1 intersect set2) // [3, 4]
println(set1 subtract set2) // [1, 2]
}
```
## Map
### Immutable Map
```kotlin
fun main() {
val capitalCities = mapOf(
"USA" to "Washington D.C.",
"UK" to "London",
"France" to "Paris"
)
println(capitalCities["USA"]) // Washington D.C.
println(capitalCities.getOrDefault("Germany", "Unknown")) // Unknown
println(capitalCities.keys) // [USA, UK, France]
println(capitalCities.values) // [Washington D.C., London, Paris]
println(capitalCities.entries) // All entries
// Iterate
for ((country, city) in capitalCities) {
println("$country -> $city")
}
}
```
### Mutable Map
```kotlin
fun main() {
val map = mutableMapOf(
"a" to 1,
"b" to 2
)
map["c"] = 3
map.put("d", 4)
map.remove("a")
map.putAll(mapOf("e" to 5, "f" to 6))
println(map) // {b=2, c=3, d=4, e=5, f=6}
}
```
## Array vs Collections
Arrays have fixed size and are more performant for primitive types:
```kotlin
fun main() {
// Arrays
val intArray = intArrayOf(1, 2, 3, 4, 5)
val stringArray = arrayOf("a", "b", "c")
// Primitive arrays (more efficient)
val byteArray = ByteArray(5) // [0, 0, 0, 0, 0]
val charArray = CharArray(3) { it + 'a' } // [a, b, c]
// Collections
val list = listOf(1, 2, 3)
val set = setOf(1, 2, 3)
}
```
## Collection Functions
### Filter, Map, Reduce
```kotlin
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// Filter even numbers
val evens = numbers.filter { it % 2 == 0 }
println(evens) // [2, 4, 6, 8, 10]
// Map - transform elements
val doubled = numbers.map { it * 2 }
println(doubled) // [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
// Reduce - combine elements
val sum = numbers.reduce { acc, n -> acc + n }
println(sum) // 55
// Fold - reduce with initial value
val product = numbers.fold(1) { acc, n -> acc * n }
println(product) // 3628800
}
```
### More Functions
```kotlin
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
println(numbers.any { it > 3 }) // true
println(numbers.all { it > 0 }) // true
println(numbers.none { it < 0 }) // true
println(numbers.count { it % 2 == 0 }) // 2
val doubled = numbers.flatMap { listOf(it, it * 10) }
println(doubled) // [1, 10, 2, 20, 3, 30, 4, 40, 5, 50]
val nested = listOf(listOf(1, 2), listOf(3, 4))
println(nested.flatten()) // [1, 2, 3, 4]
}
```
### Chaining Operations
```kotlin
fun main() {
val words = listOf("hello", "world", "kotlin", "is", "awesome")
val result = words
.filter { it.length > 3 }
.map { it.uppercase() }
.sorted()
.joinToString("-")
println(result) // AWESOME-HELLO-KOTLIN-WORLD
}
```
### Grouping
```kotlin
fun main() {
val words = listOf("apple", "banana", "apricot", "blueberry", "cherry")
val grouped = words.groupBy { it.first() }
println(grouped)
// {a=[apple, apricot], b=[banana, blueberry], c=[cherry]}
val byLength = words.groupBy { it.length }
println(byLength)
// {5=[apple], 6=[banana, cherry], 7=[apricot, blueberry]}
}
```
## Sequences
Sequences evaluate lazily, avoiding intermediate collections:
```kotlin
fun main() {
val numbers = (1..10_000).toList()
// Regular collection - creates intermediate collections
val result1 = numbers
.map { it * 2 }
.filter { it % 3 == 0 }
.take(5)
println(result1)
// Sequence - evaluates lazily
val result2 = numbers
.asSequence()
.map { it * 2 }
.filter { it % 3 == 0 }
.take(5)
.toList()
println(result2)
}
```
### When to Use Sequences
```kotlin
fun main() {
// Large collections with multiple operations
// or chain of map/filter operations
// For small collections, regular lists are fine
val small = listOf(1, 2, 3, 4, 5)
println(small.map { it * 2 }.filter { it > 5 })
}
```
## Summary
- `listOf()` creates immutable lists, `mutableListOf()` for mutable
- `setOf()` creates immutable sets (no duplicates)
- `mapOf()` creates immutable maps (key-value pairs)
- Collection functions: `filter`, `map`, `reduce`, `fold`, `flatMap`
- Sequences evaluate lazily with `asSequence()`
- Use `forEach` for side effects, `map/filter` for transformations
- Chaining operations creates readable, functional code
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →