Kotlinlearncs.online LogoJava

    ← Prev

    Index

    Next →

    Kotlin
    Java
    • Practice with Collections : 22

    • Maps and Sets : 21

    • Lists and Type Parameters : 20

    • Imports and Libraries : 19

    • Multidimensional Arrays : 18

    • Practice with Strings : 17

    • null : 16

    • Algorithms and Strings : 15

    • Strings : 14

    • Functions and Algorithms : 13

    • Practice with Functions : 12

    • More About Functions : 11

    • Errors and Debugging : 10

    • Functions : 9

    • Practice with Loops and Algorithms : 8

    • Algorithms I : 7

    • Loops : 6

    • Arrays : 5

    • Compound Conditionals : 4

    • Conditional Expressions and Statements : 3

    • Operations on Variables : 2

    • Variables and Types : 1

    • Hello, world! : 0

    Maps and Sets

    var scores = mutableMapOf<String, Int>()
    scores["you@illinois.edu"] = 100
    scores["me@illinois.edu"] = 100
    println(scores)

    This lesson introduces two new extremely useful data structures: maps and sets. Together, maps and lists can be used to solve almost any problem. And sets have their uses as well. So let’s get started!

    Maps
    Maps

    Maps represent a fundamentally new data structure for us to consider. So far we’ve looked at data structures that put items in order—like arrays and lists. We’ve also discussed using higher-dimensional arrays when needed to represent higher-dimensional data.

    Maps are quite different. They don’t put items in order. Rather, they allow us to store and look up mappings between one thing and other.

    More specifically, maps store mappings between keys and values. Each key in a map maps to just one value. However, the same value can be mapped to by multiple keys.

    Map Operations
    Map Operations

    Let’s make this more concrete by looking at a few examples. Just like Kotlin Lists, Maps are built right in and don’t require an imports:

    var map = mutableMapOf<String, String>()

    Note that, like Lists, Kotlin Maps also utilize type parameters within the angle brackets: <String, String> in the example above. However, Maps require two type parameters: one for the key, and a second for the value. Similar to Lists, Kotlin has both mutable and immutable Maps. We’ll be working primarily with mutable ones.

    We can also initialize a Map with some initial values, which allows Kotlin to infer the type of the Map:

    var map = mutableMapOf(1 to "one", 2 to "two")
    println(map) // inferred to have type parameters <Int, String>

    Note the 1 to "one" syntax above, which adds a mapping to the map between 1 (the key) and “one” (the value).

    The first map we created above can be used to map Strings to other Strings:

    var map = mutableMapOf<String, String>()
    map["challen"] = "Geoffrey Challen"
    map["colleenl"] = "Colleen Lewis"
    println(map)
    map["challen"] = "Geoff Challen"
    println(map)

    We can add mappings to our Map using bracket notation, similar to what we used for modifying arrays and lists! But instead of just integers inside the brackets, now we put the key inside the brackets and the value on the right side of the assignment. So map["challen"] = "Geoff Challen" adds a mapping to the map between “challen” (the key) and “Geoff Challen” (the value). We also show how a second assignment to “challen” overwrites the first, since each key in the map maps to a single value.

    var map = mutableMapOf<String, String>()
    map["student1"] = "A Student"
    map["student2"] = "A Student"
    println(map)

    In the example above, we show how we can establish two mappings to the same value—both “student1” and “student2” initially map to “A Student”.

    var map = mutableMapOf<String, String>()
    map["challen"] = "Geoff Challen"
    map["colleenl"] = "Colleen Lewis"
    println(map["challen"])
    println(map["student1"])

    To retrieve values from a Map we also use bracket notation and place the key to retrieve inside the brackets. The result is the value for the key, or null if the map does not contain that key. Sometimes we also refer to this as looking up the key in the map: so looking up the mapping for “challen” or “student1” in the example above.

    The Elvis Operator
    The Elvis Operator

    As a brief but useful digression, one of the useful operators that Kotlin provides for working with null safely is called the “null-coalescing” operator. Or, more colorfully, the “Elvis operator”, for reasons that will be obvious shortly.

    The Elvis operator evaluates to the left side if it is not null, otherwise to its right side:

    var s: String? = null
    println(s ?: "right side") // s is null, so ?: evaluates to the right side
    s = "left side"
    println(s ?: "right side") // s is not null, so ?: evaluates to the left side

    The Elvis operator is particularly useful when using Kotlin Maps, as we’ll show in the following example, since it allows us to set a default value to use when a map does not contain a particular key.

    Map Example
    Map Example

    Maps are great for solving problems where we need to save and look up information based on a key. Let’s look at an example that may hit close to home: Recording scores on a homework problem!

    var scores = """
    you@illinois.edu,0
    you@illinois.edu,9
    me@illinois.edu,0
    you@illinois.edu,10
    you@illinois.edu,1
    me@illinois.edu,1
    me@illinois.edu,0
    you@illinois.edu,0"""
    fun computeScores(input: String): Map<String, Integer> {
    var map = mutableMapOf<String, Integer>()
    // Parse the CSV containing scores
    for (line in input.trim().split("\n")) {
    var parts = line.split(",")
    var email = parts[0]
    var score = parts[1].toInt()
    println("$email -> $score")
    }
    return map
    }
    println(computeScores(scores))

    Map Iteration
    Map Iteration

    If you want to iterate over all of the mappings in a Kotlin Map, there are a few different ways to do that:

    var map = mutableMapOf(1 to "one", 2 to "two", 4 to "four")
    for (entry in map) {
    // each entry has a .key and a .value property
    println(entry.key)
    println(entry.value)
    }
    // new syntax that we haven't discussed yet
    for ((key, value) in map) {
    println(key)
    println(value)
    }
    // map.keys will be a list of all the map keys, similar to .indices
    for (key in map.keys) {
    println(key)
    println(map[key])
    }

    Practice: Word Count With Map

    Created By: Geoffrey Challen
    / Version: 2021.9.0

    Given a String containing words separated by the "_" character, write a method wordCount that returns a Map<String, Int> containing the number of times that each part appears in the String.

    So, for example, given the String "Xyz_Chuchu_Chuchu_Xyz_Ferdie", you would return a map with three mappings: "Xyz" to 2, "Chuchu" to 2, and "Ferdie" to 1.

    Sets
    Sets

    Before we wrap up, let’s briefly examine one other potentially-useful data structure: sets. A set represents an unordered collection of distinct elements. We can add and remove items from a set, but the set either contains the item or does not, which we can test using .contains. Items in a set don’t have an index and are not ordered or counted.

    // set initialization
    var set = mutableSetOf<Int>()
    // adding items
    set.add(1)
    println(set)
    set += 1 // same as set.add(1)
    println(set)
    set += 2
    println(set)
    // membership testing
    println(set.contains(2))
    // set iteration
    for (item in set) {
    println(item)
    }
    // item removal
    set.remove(1)
    println(set)
    set -= 2 // same as set.remove(2)
    println(set)

    Sets are generally less useful that lists or maps. But they do come in hand sometimes, particularly when you need to record membership but don’t care about counts or ordering. Let’s look at an example where a set might come in handy:

    var attendance = """
    Kermit
    Gaffer
    Gonzo
    gonzo
    Gonzo
    Scooter
    Waldorf
    GONZO
    Fozzie
    Gaffer"""

    Homework: Word Lengths With Map

    Created By: Geoffrey Challen
    / Version: 2021.9.0

    Given a String? containing words separated by the " " (space) character, write a method wordLengths that return a Map<String, Int> mapping each word that is contained in the String to its length. require that the passed String? is not null.

    So, for example, given the String "Wow that is amazing", you would return a map with four mappings: "Wow" to 3, "that" to 4, "is" to 2, and "amazing" to 7.

    Note that you should not need any import statements, since Lists are built-in to Kotlin and always available.

    More Practice

    Need more practice? Head over to the practice page.