Kotlin Map

A Kotlin Map is a collection interface that represents a group of key-value pairs where each key is unique and maps to exactly one value. Kotlin Map comes in two primary variants: immutable maps (read-only) and mutable maps (modifiable). The Kotlin Map interface provides various methods to access, search, and manipulate data efficiently.

Kotlin Map is particularly useful when you need to establish relationships between data elements, such as storing user preferences, configuration settings, or mapping database records to objects in your Kotlin applications.

Types of Kotlin Map

Immutable Map (Read-Only Map)

An immutable Kotlin Map cannot be modified after creation. Once you create an immutable map, you cannot add, remove, or update its elements.

val immutableMap = mapOf("name" to "John", "age" to 25)  

Mutable Map

A mutable Kotlin Map allows you to modify its contents after creation. You can add new key-value pairs, remove existing ones, or update values.

val mutableMap = mutableMapOf("name" to "John", "age" to 25)  

HashMap

Kotlin HashMap is a mutable map implementation that uses hash table for storage, providing fast access to elements.

val hashMap = hashMapOf("country" to "USA", "city" to "New York")  

LinkedHashMap

LinkedHashMap maintains the insertion order of elements while providing HashMap-like performance.

val linkedHashMap = linkedMapOf("first" to 1, "second" to 2)  

SortedMap

SortedMap keeps its elements sorted according to the natural ordering of keys or a custom comparator.

val sortedMap = sortedMapOf("zebra" to 1, "apple" to 2, "banana" to 3)  

Creating Kotlin Maps

Using mapOf() Function

The mapOf() function creates an immutable Kotlin Map with specified key-value pairs.

val studentGrades = mapOf(  
    "Alice" to 95,  
    "Bob" to 87,  
    "Charlie" to 92  
)  

Using mutableMapOf() Function

The mutableMapOf() function creates a mutable Kotlin Map that can be modified after creation.

val inventory = mutableMapOf(  
    "laptops" to 15,  
    "phones" to 30,  
    "tablets" to 8  
)  

Using to Infix Function

The to infix function creates Pair objects that can be used to initialize Kotlin Maps.

val colors = mapOf(  
    "red" to "#FF0000",  
    "green" to "#00FF00",  
    "blue" to "#0000FF"  
)  

Using Pair Constructor

You can also use the Pair constructor explicitly to create key-value associations.

val coordinates = mapOf(  
    Pair("x", 10),  
    Pair("y", 20),  
    Pair("z", 30)  
)  

Accessing Elements in Kotlin Map

Using get() Method

The get() method retrieves the value associated with a specific key in the Kotlin Map.

val userInfo = mapOf("username" to "john_doe", "email" to "[email protected]")  
val username = userInfo.get("username") // Returns "john_doe"  

Using Index Operator []

The index operator provides a convenient way to access map elements using square brackets.

val prices = mapOf("apple" to 1.50, "banana" to 0.75, "orange" to 2.00)  
val applePrice = prices["apple"] // Returns 1.50  

Using getValue() Method

The getValue() method returns the value for a key, throwing an exception if the key doesn’t exist.

val settings = mapOf("theme" to "dark", "language" to "english")  
val theme = settings.getValue("theme") // Returns "dark"  

Using getOrDefault() Method

The getOrDefault() method returns the value for a key or a default value if the key is not found.

val config = mapOf("timeout" to 30, "retries" to 3)  
val maxConnections = config.getOrDefault("maxConnections", 100) // Returns 100  

Using getOrElse() Method

The getOrElse() method returns the value for a key or executes a lambda function if the key is not found.

val cache = mapOf("user1" to "data1", "user2" to "data2")  
val userData = cache.getOrElse("user3") { "default_data" } // Returns "default_data"  

Modifying Mutable Kotlin Maps

Adding Elements with put() Method

The put() method adds a new key-value pair to a mutable Kotlin Map or updates an existing key’s value.

val shoppingCart = mutableMapOf("bread" to 2, "milk" to 1)  
shoppingCart.put("eggs", 12) // Adds eggs with quantity 12  

Adding Elements with Index Operator

You can use the index operator to add or update elements in a mutable Kotlin Map.

val scores = mutableMapOf("math" to 85, "science" to 90)  
scores["history"] = 88 // Adds history with score 88  

Adding Multiple Elements with putAll()

The putAll() method adds all key-value pairs from another map to the current mutable Kotlin Map.

val baseConfig = mutableMapOf("debug" to true, "version" to "1.0")  
val additionalConfig = mapOf("author" to "Developer", "year" to 2024)  
baseConfig.putAll(additionalConfig)  

Removing Elements with remove()

The remove() method removes a key-value pair from a mutable Kotlin Map.

val todoList = mutableMapOf("task1" to "completed", "task2" to "pending", "task3" to "cancelled")  
todoList.remove("task3") // Removes task3 from the map  

Clearing All Elements

The clear() method removes all elements from a mutable Kotlin Map.

val tempData = mutableMapOf("temp1" to 25, "temp2" to 30)  
tempData.clear() // Removes all elements  

Kotlin Map Properties

size Property

The size property returns the number of key-value pairs in the Kotlin Map.

val fruits = mapOf("apple" to 5, "banana" to 3, "orange" to 7)  
println("Map size: ${fruits.size}") // Output: Map size: 3  

isEmpty() Method

The isEmpty() method checks if the Kotlin Map contains no elements.

val emptyMap = mapOf<String, Int>()  
println("Is empty: ${emptyMap.isEmpty()}") // Output: Is empty: true  

isNotEmpty() Method

The isNotEmpty() method checks if the Kotlin Map contains at least one element.

val dataMap = mapOf("key1" to "value1")  
println("Is not empty: ${dataMap.isNotEmpty()}") // Output: Is not empty: true  

keys Property

The keys property returns a set containing all keys in the Kotlin Map.

val countryCapitals = mapOf("USA" to "Washington", "France" to "Paris", "Japan" to "Tokyo")  
val countries = countryCapitals.keys  
println("Countries: $countries") // Output: Countries: [USA, France, Japan]  

values Property

The values property returns a collection containing all values in the Kotlin Map.

val ageMap = mapOf("Alice" to 25, "Bob" to 30, "Charlie" to 35)  
val ages = ageMap.values  
println("Ages: $ages") // Output: Ages: [25, 30, 35]  

entries Property

The entries property returns a set of key-value pairs as Map.Entry objects.

val gradeMap = mapOf("Math" to "A", "Science" to "B", "History" to "A+")  
for (entry in gradeMap.entries) {  
    println("${entry.key}: ${entry.value}")  
}  

Kotlin Map Operations

Checking Key Existence with containsKey()

The containsKey() method checks if a specific key exists in the Kotlin Map.

val inventory = mapOf("widgets" to 100, "gadgets" to 50, "tools" to 25)  
val hasWidgets = inventory.containsKey("widgets") // Returns true  

Checking Value Existence with containsValue()

The containsValue() method checks if a specific value exists in the Kotlin Map.

val statusMap = mapOf("server1" to "online", "server2" to "offline", "server3" to "online")  
val hasOfflineServer = statusMap.containsValue("offline") // Returns true  

Filtering Kotlin Map

The filter() method creates a new map containing only elements that match a given predicate.

val numbers = mapOf("one" to 1, "two" to 2, "three" to 3, "four" to 4)  
val evenNumbers = numbers.filter { it.value % 2 == 0 }  
println("Even numbers: $evenNumbers") // Output: Even numbers: {two=2, four=4}  

Mapping Values with mapValues()

The mapValues() method creates a new map with the same keys but transformed values.

val prices = mapOf("apple" to 1.0, "banana" to 0.5, "orange" to 1.5)  
val discountedPrices = prices.mapValues { it.value * 0.9 }  
println("Discounted prices: $discountedPrices")  

Mapping Keys with mapKeys()

The mapKeys() method creates a new map with transformed keys but the same values.

val usernames = mapOf("user1" to "John", "user2" to "Jane", "user3" to "Bob")  
val uppercaseKeys = usernames.mapKeys { it.key.uppercase() }  
println("Uppercase keys: $uppercaseKeys")  

Iterating Over Kotlin Maps

Using for Loop with entries

You can iterate over a Kotlin Map using a for loop with the entries property.

val productPrices = mapOf("laptop" to 999.99, "mouse" to 29.99, "keyboard" to 79.99)  
for ((product, price) in productPrices) {  
    println("$product costs $${price}")  
}  

Using forEach() Method

The forEach() method executes a lambda function for each key-value pair in the Kotlin Map.

val temperatures = mapOf("Monday" to 25, "Tuesday" to 28, "Wednesday" to 22)  
temperatures.forEach { (day, temp) ->  
    println("$day: ${temp}°C")  
}  

Using for Loop with keys

You can iterate over map keys and access corresponding values.

val studentScores = mapOf("Alice" to 95, "Bob" to 87, "Charlie" to 92)  
for (student in studentScores.keys) {  
    println("$student scored ${studentScores[student]} points")  
}  

Advanced Kotlin Map Operations

Merging Maps with plus() Operator

The plus operator creates a new map by combining two maps, with the second map’s values taking precedence for duplicate keys.

val baseSettings = mapOf("theme" to "light", "fontSize" to 12)  
val userSettings = mapOf("fontSize" to 14, "notifications" to true)  
val mergedSettings = baseSettings + userSettings  
println("Merged settings: $mergedSettings")  

Converting Map to List

You can convert a Kotlin Map to a list of pairs using the toList() method.

val colorCodes = mapOf("red" to "#FF0000", "green" to "#00FF00", "blue" to "#0000FF")  
val colorList = colorCodes.toList()  
println("Color list: $colorList")  

Converting List to Map

You can convert a list of pairs to a Kotlin Map using the toMap() method.

val pairList = listOf("name" to "John", "age" to 30, "city" to "New York")  
val personMap = pairList.toMap()  
println("Person map: $personMap")  

Grouping with groupBy()

The groupBy() method groups elements by a key selector function.

val words = listOf("apple", "banana", "cherry", "apricot", "blueberry")  
val groupedByFirstLetter = words.groupBy { it.first() }  
println("Grouped by first letter: $groupedByFirstLetter")  

Complete Kotlin Map Example

Here’s a comprehensive example demonstrating various Kotlin Map operations in a practical scenario:

import kotlin.collections.*  
  
fun main() {  
    // Creating different types of maps  
    println("=== Creating Kotlin Maps ===")  
      
    // Immutable map  
    val studentGrades = mapOf(  
        "Alice" to 95,  
        "Bob" to 87,  
        "Charlie" to 92,  
        "Diana" to 89,  
        "Edward" to 76  
    )  
    println("Student grades: $studentGrades")  
      
    // Mutable map  
    val inventory = mutableMapOf(  
        "laptops" to 15,  
        "phones" to 30,  
        "tablets" to 8  
    )  
    println("Initial inventory: $inventory")  
      
    // HashMap  
    val userProfiles = hashMapOf(  
        "john_doe" to "John Doe",  
        "jane_smith" to "Jane Smith",  
        "bob_johnson" to "Bob Johnson"  
    )  
    println("User profiles: $userProfiles")  
      
    // LinkedHashMap (maintains insertion order)  
    val orderedTasks = linkedMapOf(  
        "morning" to "Exercise",  
        "afternoon" to "Work",  
        "evening" to "Dinner",  
        "night" to "Sleep"  
    )  
    println("Ordered tasks: $orderedTasks")  
      
    // SortedMap (keeps elements sorted)  
    val sortedScores = sortedMapOf(  
        "zebra" to 100,  
        "apple" to 85,  
        "banana" to 92  
    )  
    println("Sorted scores: $sortedScores")  
      
    println("\n=== Accessing Map Elements ===")  
      
    // Different ways to access elements  
    val username = userProfiles["john_doe"]  
    println("Username: $username")  
      
    val aliceGrade = studentGrades.getValue("Alice")  
    println("Alice's grade: $aliceGrade")  
      
    val defaultTimeout = mapOf("retries" to 3).getOrDefault("timeout", 30)  
    println("Default timeout: $defaultTimeout")  
      
    val userData = userProfiles.getOrElse("unknown_user") { "Guest User" }  
    println("User data: $userData")  
      
    println("\n=== Modifying Mutable Maps ===")  
      
    // Adding elements  
    inventory["monitors"] = 12  
    inventory.put("keyboards", 25)  
    println("Updated inventory: $inventory")  
      
    // Adding multiple elements  
    val newItems = mapOf("mice" to 40, "webcams" to 18)  
    inventory.putAll(newItems)  
    println("Inventory after adding multiple items: $inventory")  
      
    // Removing elements  
    inventory.remove("tablets")  
    println("Inventory after removing tablets: $inventory")  
      
    println("\n=== Map Properties and Operations ===")  
      
    // Map properties  
    println("Student grades size: ${studentGrades.size}")  
    println("Is inventory empty: ${inventory.isEmpty()}")  
    println("Is student grades not empty: ${studentGrades.isNotEmpty()}")  
      
    // Keys, values, and entries  
    println("Student names: ${studentGrades.keys}")  
    println("Grade values: ${studentGrades.values}")  
    println("Inventory entries:")  
    for (entry in inventory.entries) {  
        println("  ${entry.key}: ${entry.value}")  
    }  
      
    // Checking existence  
    val hasAlice = studentGrades.containsKey("Alice")  
    println("Has Alice in grades: $hasAlice")  
      
    val hasGrade95 = studentGrades.containsValue(95)  
    println("Has grade 95: $hasGrade95")  
      
    println("\n=== Filtering and Transformation ===")  
      
    // Filtering  
    val highGrades = studentGrades.filter { it.value >= 90 }  
    println("High grades (>=90): $highGrades")  
      
    val lowInventory = inventory.filter { it.value < 20 }  
    println("Low inventory items (<20): $lowInventory")  
      
    // Mapping values  
    val gradePercentages = studentGrades.mapValues { "${it.value}%" }  
    println("Grade percentages: $gradePercentages")  
      
    // Mapping keys  
    val uppercaseGrades = studentGrades.mapKeys { it.key.uppercase() }  
    println("Uppercase student names: $uppercaseGrades")  
      
    println("\n=== Iteration Examples ===")  
      
    // Iterating with destructuring  
    println("Student grade report:")  
    for ((student, grade) in studentGrades) {  
        val status = if (grade >= 90) "Excellent" else if (grade >= 80) "Good" else "Needs Improvement"  
        println("  $student: $grade ($status)")  
    }  
      
    // Using forEach  
    println("Inventory report:")  
    inventory.forEach { (item, quantity) ->  
        val status = if (quantity > 20) "Well Stocked" else "Low Stock"  
        println("  $item: $quantity units ($status)")  
    }  
      
    println("\n=== Advanced Operations ===")  
      
    // Merging maps  
    val baseConfig = mapOf("version" to "1.0", "debug" to false)  
    val userConfig = mapOf("debug" to true, "theme" to "dark")  
    val finalConfig = baseConfig + userConfig  
    println("Final configuration: $finalConfig")  
      
    // Converting to list and back  
    val gradeList = studentGrades.toList()  
    println("Grades as list: $gradeList")  
      
    val backToMap = gradeList.toMap()  
    println("Back to map: $backToMap")  
      
    // Grouping operation  
    val words = listOf("apple", "banana", "cherry", "apricot", "blueberry", "avocado")  
    val wordGroups = words.groupBy { it.first().uppercaseChar() }  
    println("Words grouped by first letter: $wordGroups")  
      
    // Complex filtering and transformation  
    val processedGrades = studentGrades  
        .filter { it.value >= 80 }  
        .mapValues { entry ->  
            when {  
                entry.value >= 95 -> "A+"  
                entry.value >= 90 -> "A"  
                entry.value >= 85 -> "B+"  
                else -> "B"  
            }  
        }  
    println("Letter grades for students with 80+: $processedGrades")  
}  

Output:

=== Creating Kotlin Maps ===  
Student grades: {Alice=95, Bob=87, Charlie=92, Diana=89, Edward=76}  
Initial inventory: {laptops=15, phones=30, tablets=8}  
User profiles: {bob_johnson=Bob Johnson, john_doe=John Doe, jane_smith=Jane Smith}  
Ordered tasks: {morning=Exercise, afternoon=Work, evening=Dinner, night=Sleep}  
Sorted scores: {apple=85, banana=92, zebra=100}  
  
=== Accessing Map Elements ===  
Username: John Doe  
Alice's grade: 95  
Default timeout: 30  
User data: Guest User  
  
=== Modifying Mutable Maps ===  
Updated inventory: {laptops=15, phones=30, tablets=8, monitors=12, keyboards=25}  
Inventory after adding multiple items: {laptops=15, phones=30, tablets=8, monitors=12, keyboards=25, mice=40, webcams=18}  
Inventory after removing tablets: {laptops=15, phones=30, monitors=12, keyboards=25, mice=40, webcams=18}  
  
=== Map Properties and Operations ===  
Student grades size: 5  
Is inventory empty: false  
Is student grades not empty: true  
Student names: [Alice, Bob, Charlie, Diana, Edward]  
Grade values: [95, 87, 92, 89, 76]  
Inventory entries:  
  laptops: 15  
  phones: 30  
  monitors: 12  
  keyboards: 25  
  mice: 40  
  webcams: 18  
Has Alice in grades: true  
Has grade 95: true  
  
=== Filtering and Transformation ===  
High grades (>=90): {Alice=95, Charlie=92}  
Low inventory items (<20): {laptops=15, monitors=12}  
Grade percentages: {Alice=95%, Bob=87%, Charlie=92%, Diana=89%, Edward=76%}  
Uppercase student names: {ALICE=95, BOB=87, CHARLIE=92, DIANA=89, EDWARD=76}  
  
=== Iteration Examples ===  
Student grade report:  
  Alice: 95 (Excellent)  
  Bob: 87 (Good)  
  Charlie: 92 (Excellent)  
  Diana: 89 (Good)  
  Edward: 76 (Needs Improvement)  
Inventory report:  
  laptops: 15 units (Low Stock)  
  phones: 30 units (Well Stocked)  
  monitors: 12 units (Low Stock)  
  keyboards: 25 units (Well Stocked)  
  mice: 40 units (Well Stocked)  
  webcams: 18 units (Low Stock)  
  
=== Advanced Operations ===  
Final configuration: {version=1.0, debug=true, theme=dark}  
Grades as list: [(Alice, 95), (Bob, 87), (Charlie, 92), (Diana, 89), (Edward, 76)]  
Back to map: {Alice=95, Bob=87, Charlie=92, Diana=89, Edward=76}  
Words grouped by first letter: {A=[apple, apricot, avocado], B=[banana, blueberry], C=[cherry]}  
Letter grades for students with 80+: {Alice=A+, Bob=B+, Charlie=A, Diana=B}