Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Maps and Sets | Control Flow and Collections
Android Development with Kotlin
course content

Contenido del Curso

Android Development with Kotlin

Android Development with Kotlin

1. Kotlin Basics
2. Control Flow and Collections
3. Object-Oriented Programming in Kotlin

Maps and Sets

Continuing our discussion on collections in Kotlin, this chapter will cover two quite interesting types of collections: Maps and Sets.

Map

Maps are collections of "key-value" pairs. In Kotlin, they are represented by the Map interface and have two main implementations: HashMap and LinkedHashMap.

This representation is very convenient when two elements are related. For example, a user ID and their name or a product type and its quantity.

However, the key's value should be unique because we use it to retrieve values when accessing elements. Otherwise, collisions may occur, which we’ll discuss later.

So, let’s see how we can create a map and use its values with an example where the product is the key and its quantity is the value:

kt

Main

copy
12345678910
fun main() { val product1Name: String = "Tomato" var product1Quantity: Int = 392 val product2Name: String = "Apples" var product2Quantity: Int = 161 val productsQuantity = mapOf(product1Name to product1Quantity, product2Name to product2Quantity) println(productsQuantity) }

We created a data structure called a Map and then filled it with some test data. This data structure is stored in the productsQuantity variable, where the key is the product name and the value is the quantity of that product in stock.

To retrieve data from the map, we can use a syntax similar to what we used with arrays, but instead of accessing data by index, we will access it by key:

kt

Main

copy
12345678910111213141516
fun main() { val product1Name: String = "Tomato" var product1Quantity: Int = 392 val product2Name: String = "Apples" var product2Quantity: Int = 161 val productsQuantity = mapOf(product1Name to product1Quantity, product2Name to product2Quantity) // accessing the elements by their key val TomatoQuantity = productsQuantity["Tomato"] val AppleQuantity = productsQuantity["Apples"] println("The quantity of Tomato is $TomatoQuantity") println("The quantity of Apples is $AppleQuantity") }

We can also change the value of elements by accessing them by key, just like elements in an array.

However, for this, we need to use a different way of initializing the map. The map created with the mapOf() method is immutable, meaning its elements cannot be changed.

To create a mutable map, we need to use the mutableMapOf() method, and the initialization will look like this:

kt

Main

copy
1
val productsQuantity = mutableMapOf(product1Name to product1Quantity, product2Name to product2Quantity)

Now let's write a method that will subtract the quantity of the purchased product from this map (simulating a user buying something from our online store):

kt

Main

copy
1234567891011121314151617181920
fun main() { val product1Name: String = "Tomato" var product1Quantity: Int = 392 val product2Name: String = "Apples" var product2Quantity: Int = 161 val productsQuantity = mutableMapOf(product1Name to product1Quantity, product2Name to product2Quantity) println("Initial map values: $productsQuantity") subtractProduct(productsQuantity, "Tomato", 100) println("Updated map values: $productsQuantity") } fun subtractProduct(map: MutableMap<String, Int>, productName: String, purchasedQuantity: Int) { val previousQuantity = map[productName] val newQuantity = previousQuantity!! - purchasedQuantity map[productName] = newQuantity }

You don't need to pay attention to the !! operator right now; it ensures type safety and is used for handling null values. We will discuss this later in this section.

As you can see, the function is simple and takes three parameters:

  • The map we are working with
  • The name of the purchased product
  • The quantity of the purchased product

You might have noticed that when specifying the map in the parameters, we used a new construction: <String, Int>. This is called a generic, often used with lists.

A Brief Overview of Generics

A generic is a construct used during class initialization (we will talk about this in the next section) that defines the TYPE of parameters that will be used.

In the case of a map, we define the data types that will be the key and value. For the map we created, the key's data type is String, and the value's data type is Int. These data types are specified within diamond brackets (<>).

If we want to initialize a map where the key's data type is Int and the value's data type is Float, we would initialize this map using the following syntax:

kt

Main

copy
1
val customMap: MutableMap<Int, Float> = mutableMapOf(some values)

This way, we tell Kotlin which data types we plan to use for a specific map. Later in this section, we will look at generics in more detail, but for now, you should remember what they are and how to use them when creating maps.

Generics can also be used with lists, which we studied in the previous chapter, if you want the list to contain a specific data type, for example like this:

kt

Main

copy
123456789101112
fun main() { val integerList: List<Int> = listOf(10, 15, 30, 22) val stringList: List<String> = listOf("Banana", "Apple", "Onion") // You can use "Any" inside generic to make a list mixed. val mixedList: List<Any> = listOf(10, 12.3, "banana", true, 29910) println("List with Integer values: $integerList," + "\n" + "List with String values: $stringList, " + "\n" + "List with any values: $mixedList") // `\n` mean moving to the next line }

MutableMap

I think there shouldn't be any questions about generics at this point, so we can move on.

With a mutable map, we can also directly add, remove, and modify values. It's straightforward; we simply assign new values to our map. For example, let's create a map that holds two values. The key will be a string, and the value will be an integer. This map will simply contain numbers:

kt

Main

copy
1234567891011121314
fun main() { var mutableMap: MutableMap<String, Int> = mutableMapOf("One" to 1, "Two" to 2) println("Initial map: $mutableMap") mutableMap["Three"] = 3 mutableMap["Four"] = 4 println("Map after adding 2 elements: $mutableMap") mutableMap["Two"] = 22 // Changing value of element with key "Two" println("Map after changing element: $mutableMap") mutableMap.remove("Three") println("Map after removing element: $mutableMap") }

As you can see, we access and modify elements using the syntax mapName[key] = newValue. This allows us to add new elements by specifying a key that doesn't yet exist in the map or to update existing elements by specifying the key of the value we want to change.

Additionally, we can remove elements from a mutable map using the method mapName.remove(key).

We can also add or update element values using the method mapName.put(key, newValue).

Below is the same code as before, but this time we add and modify values in the map using the put method instead of reassigning the values:

kt

Main

copy
1234567891011121314
fun main() { var mutableMap: MutableMap<String, Int> = mutableMapOf("One" to 1, "Two" to 2) println("Initial map: $mutableMap") mutableMap.put("Three", 3) mutableMap.put("Four", 4) println("Map after adding 2 elements: $mutableMap") mutableMap.put("Two", 22) // Changing value of element with key "Two" println("Map after changing element: $mutableMap") mutableMap.remove("Three") println("Map after removing element: $mutableMap") }

Which method you use is up to you; both are convenient and correct.

Checking for Element Presence

Maps also have functions that allow you to check if a specific key or value exists in the map.

For instance, you might need this when you're about to update a value associated with a specific key but are unsure if that key or value is present in the map. You can use the functions mapName.containsKey(key) and mapName.containsValue(value) for this. These methods return boolean values, either true or false.

Here's what it looks like in code:

kt

Main

copy
12345678910
fun main() { var mutableMap: MutableMap<String, Int> = mutableMapOf("One" to 1, "Two" to 2) println("Initial map: $mutableMap") val isKeyPresent: Boolean = mutableMap.containsKey("One") val isValuePresent: Boolean = mutableMap.containsValue(3) println("Map contains key \"One\"? $isKeyPresent") println("Map contains value \"3\"? $isValuePresent") }

In this simple way, we can check for the presence of specific elements in a map.

Iterating Over a Map

You can iterate over the keys, values, or key-value pairs in a map. We will use a for loop to iterate through the map. Let's go through this step by step.

Iterating Over Key-Value Pairs:

kt

Main

copy
12345678
fun main() { var mutableMap: MutableMap<String, Int> = mutableMapOf("One" to 1, "Two" to 2, "Three" to 3, "Four" to 4) println("Initial map: $mutableMap") for ((key, value) in mutableMap) { println("The key is $key, the value is $value") } }

In the initializer, we specify both values. The compiler understands that we will be iterating over the map, allowing us to use both values within the loop.

Iterating Over Keys

kt

Main

copy
12345678
fun main() { var mutableMap: MutableMap<String, Int> = mutableMapOf("One" to 1, "Two" to 2, "Three" to 3, "Four" to 4) println("Initial map: $mutableMap") for (key in mutableMap.keys) { println("The key is $key") } }

To iterate, we use the .keys property, which converts the map into a list of keys. We then simply iterate over this list, as demonstrated in the previous chapter.

Iterating Over Values

kt

Main

copy
12345678
fun main() { var mutableMap: MutableMap<String, Int> = mutableMapOf("One" to 1, "Two" to 2, "Three" to 3, "Four" to 4) println("Initial map: $mutableMap") for (value in mutableMap.values) { println("The value is $value") } }

Similarly, we use the .values property to iterate over the list of values from the map.

Additionally, there's a useful property that allows us to find out the size (number of elements) of a map:

kt

Main

copy
1234567
fun main() { var mutableMap: MutableMap<String, Int> = mutableMapOf("One" to 1, "Two" to 2, "Three" to 3, "Four" to 4) println("Initial map: $mutableMap") val sizeOfMap: Int = mutableMap.size println("The size of the map is $sizeOfMap") }

This isn’t all there is to know about maps. In the rest of the course, we will explore how to use them more and demonstrate various applications. For now, it’s important to understand that a map is a powerful tool for efficiently storing and manipulating data.

Set

In Kotlin, a Set is a collection of unique elements. Unlike lists, sets do not allow duplicate elements.

To easily remember a set, think of it as a list with unique elements.

There are two types of sets: mutable and immutable (generally, you can infer that each data structure in Kotlin has these two versions).

Let's start with immutable sets, which can be created as follows:

kt

Main

copy
12345
fun main() { val immutableSet: Set<Any> = setOf("Potato", "Tomato", 30, 30) println(immutableSet) }

We see that a Set also uses generics, and we can fill it with values at the time of declaration using the setOf(values) function.

Note that we tried to insert two identical values into the set, but when outputted, the duplicate was removed, leaving only one value, '30'.

Now, let's move on to mutable Sets:

kt

Main

copy
123456789
fun main() { var mutableSet: MutableSet<String> = mutableSetOf("Potato", "Tomato") println("Initial Set: $mutableSet") mutableSet.add("Cucumber") // Adding element mutableSet.remove("Potato") // Removing element println("Set after changes: $mutableSet") }

As you can see, a MutableSet<> is declared using the .mutableSetOf() function, and like a mutable map, it has methods for adding and removing elements.

Note

To modify an element in a Set, you should remove the element you want to change and then add the new element.

Similarly to a map, we can check for the presence of elements in a Set using the .contains() function. Here's how it looks in the code:

kt

Main

copy
12345678910
fun main() { val vegetables: MutableSet<String> = mutableSetOf("Potato", "Tomato", "Cucumber") println("Initial Set: $vegetables") val isTomatoPresent: Boolean = vegetables.contains("Tomato") val isCabbagePresent: Boolean = vegetables.contains("Cabbage") println("Is Tomato in the list? $isTomatoPresent " + "\n" + "Is Cabbage in the list? $isCabbagePresent") }

We can also use the size method, which will return the size (number of elements) of the set, similar to how it works with lists or maps.

Note

All methods that work with sets also work with lists because they are very similar data structures, with the only difference being the uniqueness of elements.

Iterating Over Set Elements

Iteration over set elements is similar to iterating over list elements.

However, let's look at an example code just in case:

kt

Main

copy
12345678
fun main() { val vegetables: MutableSet<String> = mutableSetOf("Potato", "Tomato", "Cucumber") println("Initial Set: $vegetables") for (vegetable in vegetables) { println(vegetable) } }

This way, we can use a Set when we need a collection of unique elements!

Sets and Maps are powerful tools and useful data structures! Keep them in mind, and they will definitely come in handy!

1. What is a Map in Kotlin?
2. How can you make a Map mutable in Kotlin?
3. Which method is used to check if a specific key exists in a Map?
4. What is a Set in Kotlin?
5. How do you iterate over a Map in Kotlin to access both keys and values?

What is a Map in Kotlin?

Selecciona la respuesta correcta

How can you make a Map mutable in Kotlin?

Selecciona la respuesta correcta

Which method is used to check if a specific key exists in a Map?

Selecciona la respuesta correcta

What is a Set in Kotlin?

Selecciona la respuesta correcta

How do you iterate over a Map in Kotlin to access both keys and values?

Selecciona la respuesta correcta

¿Todo estuvo claro?

Sección 2. Capítulo 3
We're sorry to hear that something went wrong. What happened?
some-alt