Kotlin Maps
Maps are a fundamental collection type in Kotlin that store key-value pairs. Unlike lists or sets that store individual elements, maps maintain associations between keys and their corresponding values. If you're familiar with dictionaries in Python or hash maps in Java, Kotlin maps function similarly.
What Are Maps?
A map is a collection that holds pairs of objects, where each pair consists of a key and its value. The keys in a map are unique, meaning a map cannot contain duplicate keys. Each key maps to exactly one value, though different keys can map to the same value.
Creating Maps in Kotlin
Kotlin provides several ways to create maps:
Using mapOf()
Function
The mapOf()
function creates an immutable (read-only) map.
// Creating an immutable map with key-value pairs
val countryCapitals = mapOf(
"USA" to "Washington D.C.",
"India" to "New Delhi",
"UK" to "London",
"Japan" to "Tokyo"
)
println(countryCapitals)
Output:
{USA=Washington D.C., India=New Delhi, UK=London, Japan=Tokyo}
Using mutableMapOf()
Function
For maps that need to be modified after creation, use mutableMapOf()
:
// Creating a mutable map
val userRoles = mutableMapOf(
"[email protected]" to "ADMIN",
"[email protected]" to "USER"
)
println(userRoles)
// Adding a new entry
userRoles["[email protected]"] = "GUEST"
println("After adding: $userRoles")
// Updating an existing entry
userRoles["[email protected]"] = "PREMIUM_USER"
println("After updating: $userRoles")
// Removing an entry
userRoles.remove("[email protected]")
println("After removing: $userRoles")
Output:
{[email protected]=ADMIN, [email protected]=USER}
After adding: {[email protected]=ADMIN, [email protected]=USER, [email protected]=GUEST}
After updating: {[email protected]=ADMIN, [email protected]=PREMIUM_USER, [email protected]=GUEST}
After removing: {[email protected]=ADMIN, [email protected]=PREMIUM_USER}
Using hashMapOf()
, linkedMapOf()
, and sortedMapOf()
Kotlin provides specialized map implementations:
// HashMap - no guaranteed order
val hashMap = hashMapOf("one" to 1, "two" to 2, "three" to 3)
// LinkedHashMap - maintains insertion order
val linkedMap = linkedMapOf("one" to 1, "three" to 3, "two" to 2)
// SortedMap - sorts keys by their natural order
val sortedMap = sortedMapOf("two" to 2, "one" to 1, "three" to 3)
println("HashMap: $hashMap")
println("LinkedHashMap: $linkedMap")
println("SortedMap: $sortedMap")
Output:
HashMap: {one=1, two=2, three=3}
LinkedHashMap: {one=1, three=3, two=2}
SortedMap: {one=1, three=3, two=2}
Accessing Map Elements
Using the Indexing Operator []
val capitals = mapOf(
"France" to "Paris",
"Germany" to "Berlin",
"Italy" to "Rome"
)
// Accessing a value by key
val franceCapital = capitals["France"]
println("The capital of France is $franceCapital")
// Accessing a non-existent key returns null
val spainCapital = capitals["Spain"]
println("The capital of Spain is $spainCapital")
Output:
The capital of France is Paris
The capital of Spain is null
Using getValue()
Function
val capitals = mapOf(
"France" to "Paris",
"Germany" to "Berlin",
"Italy" to "Rome"
)
// Using getValue() - throws exception if key doesn't exist
try {
val germanyCapital = capitals.getValue("Germany")
println("The capital of Germany is $germanyCapital")
val spainCapital = capitals.getValue("Spain")
println("The capital of Spain is $spainCapital")
} catch (e: NoSuchElementException) {
println("Exception: ${e.message}")
}
Output:
The capital of Germany is Berlin
Exception: Key Spain is missing in the map.
Using Safe Access Functions
val capitals = mapOf(
"France" to "Paris",
"Germany" to "Berlin",
"Italy" to "Rome"
)
// getOrDefault - provides a default value if key doesn't exist
val spainCapital = capitals.getOrDefault("Spain", "Unknown")
println("The capital of Spain is $spainCapital")
// getOrElse - computes a default value if key doesn't exist
val ukCapital = capitals.getOrElse("UK") { "Not in database" }
println("The capital of UK is $ukCapital")
Output:
The capital of Spain is Unknown
The capital of UK is Not in database
Iterating Through Maps
Using for
Loop
val fruitPrices = mapOf(
"Apple" to 2.5,
"Banana" to 1.5,
"Orange" to 3.0,
"Grapes" to 4.5
)
println("Fruit prices:")
for ((fruit, price) in fruitPrices) {
println("$fruit costs $$price per kg")
}
Output:
Fruit prices:
Apple costs $2.5 per kg
Banana costs $1.5 per kg
Orange costs $3.0 per kg
Grapes costs $4.5 per kg
Using forEach()
val studentGrades = mapOf(
"Alice" to 92,
"Bob" to 85,
"Charlie" to 79,
"Diana" to 95
)
println("Student grades:")
studentGrades.forEach { (student, grade) ->
val performance = when {
grade >= 90 -> "Excellent"
grade >= 80 -> "Good"
grade >= 70 -> "Satisfactory"
else -> "Needs improvement"
}
println("$student: $grade - $performance")
}
Output:
Student grades:
Alice: 92 - Excellent
Bob: 85 - Good
Charlie: 79 - Satisfactory
Diana: 95 - Excellent
Map Operations
Checking if a Key or Value Exists
val inventory = mapOf(
"apple" to 25,
"banana" to 15,
"orange" to 30
)
println("Is 'apple' in inventory? ${inventory.containsKey("apple")}")
println("Is 'grapes' in inventory? ${inventory.containsKey("grapes")}")
println("Do we have any item with quantity 15? ${inventory.containsValue(15)}")
Output:
Is 'apple' in inventory? true
Is 'grapes' in inventory? false
Do we have any item with quantity 15? true
Filtering Maps
val scores = mapOf(
"Alice" to 85,
"Bob" to 72,
"Charlie" to 93,
"Diana" to 65,
"Eva" to 91
)
// Filter students who scored 80 or above
val highScorers = scores.filter { (_, score) -> score >= 80 }
println("Students with high scores: $highScorers")
// Filter students whose names start with 'A' or 'B'
val abStudents = scores.filterKeys { it.startsWith('A') || it.startsWith('B') }
println("Students with names starting with A or B: $abStudents")
Output:
Students with high scores: {Alice=85, Charlie=93, Eva=91}
Students with names starting with A or B: {Alice=85, Bob=72}
Transforming Maps
val prices = mapOf(
"shirt" to 25.0,
"pants" to 35.0,
"hat" to 15.0
)
// Apply 10% discount to all prices
val discountedPrices = prices.mapValues { (_, price) -> price * 0.9 }
println("Original prices: $prices")
println("Discounted prices: $discountedPrices")
// Convert all keys to uppercase
val uppercaseKeys = prices.mapKeys { (item, _) -> item.uppercase() }
println("With uppercase keys: $uppercaseKeys")
Output:
Original prices: {shirt=25.0, pants=35.0, hat=15.0}
Discounted prices: {shirt=22.5, pants=31.5, hat=13.5}
With uppercase keys: {SHIRT=25.0, PANTS=35.0, HAT=15.0}
Practical Examples
Simple Frequency Counter
fun main() {
val text = "The quick brown fox jumps over the lazy dog"
// Count the frequency of each word
val wordFrequency = mutableMapOf<String, Int>()
text.lowercase().split(" ").forEach { word ->
val count = wordFrequency.getOrDefault(word, 0)
wordFrequency[word] = count + 1
}
println("Word frequency in the text:")
wordFrequency.forEach { (word, count) ->
println("'$word': $count time(s)")
}
}
Output:
Word frequency in the text:
'the': 2 time(s)
'quick': 1 time(s)
'brown': 1 time(s)
'fox': 1 time(s)
'jumps': 1 time(s)
'over': 1 time(s)
'lazy': 1 time(s)
'dog': 1 time(s)
Shopping Cart Implementation
class ShoppingCart {
private val items = mutableMapOf<String, Int>()
private val prices = mapOf(
"apple" to 1.0,
"banana" to 0.5,
"orange" to 0.7,
"milk" to 2.5,
"bread" to 1.5,
"eggs" to 2.0
)
fun addItem(item: String, quantity: Int = 1) {
if (!prices.containsKey(item.lowercase())) {
println("Sorry, we don't sell $item")
return
}
val currentQuantity = items.getOrDefault(item.lowercase(), 0)
items[item.lowercase()] = currentQuantity + quantity
println("Added $quantity ${if (quantity == 1) item else "${item}s"}")
}
fun removeItem(item: String, quantity: Int = 1) {
if (!items.containsKey(item.lowercase())) {
println("$item is not in your cart")
return
}
val currentQuantity = items[item.lowercase()] ?: 0
if (currentQuantity <= quantity) {
items.remove(item.lowercase())
println("Removed all ${item}s from cart")
} else {
items[item.lowercase()] = currentQuantity - quantity
println("Removed $quantity ${if (quantity == 1) item else "${item}s"}")
}
}
fun displayCart() {
if (items.isEmpty()) {
println("Your cart is empty")
return
}
println("Your Shopping Cart:")
println("-------------------")
var total = 0.0
items.forEach { (item, quantity) ->
val itemPrice = prices[item] ?: 0.0
val itemTotal = itemPrice * quantity
total += itemTotal
println("$item: $quantity x $${itemPrice} = $${String.format("%.2f", itemTotal)}")
}
println("-------------------")
println("Total: $${String.format("%.2f", total)}")
}
}
fun main() {
val cart = ShoppingCart()
cart.addItem("Apple", 3)
cart.addItem("Milk")
cart.addItem("Bread", 2)
cart.addItem("Chocolate") // Not in stock
cart.displayCart()
cart.removeItem("Apple", 2)
cart.removeItem("Bread")
cart.displayCart()
}
Output:
Added 3 Apples
Added 1 Milk
Added 2 Breads
Sorry, we don't sell Chocolate
Your Shopping Cart:
-------------------
apple: 3 x $1.0 = $3.00
milk: 1 x $2.5 = $2.50
bread: 2 x $1.5 = $3.00
-------------------
Total: $8.50
Removed 2 Apples
Removed all breads from cart
Your Shopping Cart:
-------------------
apple: 1 x $1.0 = $1.00
milk: 1 x $2.5 = $2.50
-------------------
Total: $3.50
Summary
Maps are powerful collections in Kotlin that allow you to store and manipulate key-value pairs. In this guide, we've covered:
- Different ways to create maps: immutable, mutable, and specialized implementations
- Accessing map elements using indexing,
getValue()
, and safe access functions - Iterating through maps using
for
loops andforEach()
- Common map operations like checking for keys/values, filtering, and transforming
- Practical examples including a word frequency counter and a shopping cart implementation
Maps are essential for many real-world applications where you need to maintain associations between related data. They provide efficient lookups and offer a variety of operations to manipulate data based on keys or values.
Additional Resources
Exercises
-
Create a map that stores student names and their grades. Calculate the average grade and find the student with the highest grade.
-
Implement a simple address book using a mutable map. Add functions to add, update, and delete contacts.
-
Write a function that takes a list of strings and returns a map where the keys are the strings and the values are the frequencies of those strings in the list.
-
Implement a minimal cache system using a map. The cache should store results of expensive operations and return cached results when available.
-
Create a simple dictionary application that allows users to add word definitions, look up words, and remove words from the dictionary.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)