Lesson 3
Exploring Scala Lists: From Basics to Advanced Usage
Topic Overview and Actualization

Greetings, coding enthusiasts! Today, we're diving into Scala's diverse toolbox to unravel a fundamental data structure: Lists! Much like a shopping list or a task list, Scala allows us to create a list of items. With our eyes fixed on mastering Lists, we're geared up for a journey into the world of Scala!

Introduction to Lists in Scala

Have you ever created a to-do list? It stores your tasks in one place, right? Likewise, Scala's Lists can store multiple items of homogeneous types. There are two primary types of lists in Scala: immutable and mutable.

Immutable lists, once created, cannot be changed. This means you can't update existing elements, add new elements, or remove elements from an immutable list. On the other hand, mutable lists can be modified — you can add, change, and remove elements. Consider this example of a to-do list:

Scala
1@main def run: Unit = 2 val myToDoList = List("buy groceries", "take out the trash", "send emails") 3 println(myToDoList) // This will print the list in a nicely formatted way

By default, Lists in Scala are immutable. If you need mutable lists, Scala provides ListBuffer, which we'll explore in this lesson.

Creating Lists in Scala

To create a list in Scala, you can use the List() function. This will create an immutable list. For mutable lists, you can use ListBuffer by importing scala.collection.mutable.ListBuffer:

Scala
1import scala.collection.mutable.ListBuffer 2 3@main def run: Unit = 4 val names = List("Alice", "Bob", "Charlie") // An immutable list 5 println(names) // Prints List(Alice, Bob, Charlie) 6 7 val mutableNames = ListBuffer("Alice", "Bob", "Charlie") // A mutable list 8 mutableNames += "Dave" // Adding an element to the mutable list 9 println(mutableNames) // Prints ListBuffer(Alice, Bob, Charlie, Dave)

The import statement import scala.collection.mutable.ListBuffer is necessary to tell Scala to include the ListBuffer functionality from its library. Without this, Scala wouldn't recognize ListBuffer as a valid data structure.

Working with Immutable Lists

You can access elements in an immutable list using numeric indices. Consider that list indices in Scala start at 0:

Scala
1@main def run: Unit = 2 val fruits = List("Apple", "Banana", "Cherry") 3 println(fruits(0)) // Accessing the first element, "Apple" 4 println(fruits(2)) // Accessing the third element, "Cherry"

Note that index values should be within the range of 0 to list.length - 1. If you try to access an element with an invalid index, Scala will throw an IndexOutOfBoundsException:

Scala
1@main def run: Unit = 2 val fruits = List("Apple", "Banana", "Cherry") 3 println(fruits) // Prints List(Apple, Banana, Cherry) 4 println(fruits(5)) // This will throw an IndexOutOfBoundsException 5 println(fruits(-3)) // This will throw an IndexOutOfBoundsException

Even though we mentioned that it's not possible to add elements to immutable lists, it's possible to create a new list with additional elements. You can use the :+ or ++ operators to achieve this. These operations will return a new list and keep the original list unchanged:

Scala
1@main def run: Unit = 2 val numbers = List(1, 2, 3) 3 println(numbers) // Prints List(1, 2, 3) 4 val moreNumbers = numbers :+ 4 // Appending one element, returns a new list 5 println(moreNumbers) // Prints List(1, 2, 3, 4) 6 val evenMoreNumbers = numbers ++ List(4, 5, 6) // Appending multiple elements, returns a new list 7 println(evenMoreNumbers) // Prints List(1, 2, 3, 4, 5, 6)
Working with Mutable Lists

To create and modify mutable lists, use ListBuffer:

Scala
1import scala.collection.mutable.ListBuffer 2 3@main def run: Unit = 4 val mutableNames = ListBuffer("Alice", "Bob", "Charlie") // A mutable list 5 println(mutableNames) // Prints ListBuffer(Alice, Bob, Charlie) 6 mutableNames += "Dave" // Adding an element to the mutable list 7 println(mutableNames) // Prints ListBuffer(Alice, Bob, Charlie, Dave)

To add elements to a mutable ListBuffer, you can use += for one and ++= for multiple elements:

Scala
1import scala.collection.mutable.ListBuffer 2 3@main def run: Unit = 4 val mutableNumbers = ListBuffer(1, 2, 3) 5 println(mutableNumbers) // Prints ListBuffer(1, 2, 3) 6 mutableNumbers += 4 // Appending one element to the ListBuffer 7 println(mutableNumbers) // Prints ListBuffer(1, 2, 3, 4) 8 mutableNumbers ++= List(5, 6, 7) // Appending multiple elements to the ListBuffer 9 println(mutableNumbers) // Prints ListBuffer(1, 2, 3, 4, 5, 6, 7)

You can modify elements in a ListBuffer using their indices:

Scala
1import scala.collection.mutable.ListBuffer 2 3@main def run: Unit = 4 val mutableColors = ListBuffer("Red", "Green", "Blue") 5 println(mutableColors) // Prints ListBuffer(Red, Green, Blue) 6 mutableColors(1) = "Yellow" // Modifies the second element 7 println(mutableColors) // Prints ListBuffer(Red, Yellow, Blue)

And if you want to add elements to an existing List and get a new List as the result instead of changing the original list, you can transition from ListBuffer back to List:

Scala
1import scala.collection.mutable.ListBuffer 2 3@main def run: Unit = 4 val mutableNumbers = ListBuffer(1, 2, 3, 4, 5, 6, 7) 5 println(mutableNumbers) // Prints ListBuffer(1, 2, 3, 4, 5, 6, 7) 6 val noMoreMutable = mutableNumbers.toList 7 println(noMoreMutable) // Prints List(1, 2, 3, 4, 5, 6, 7)
Properties of Lists

Scala Lists come equipped with useful properties that work for both immutable and mutable types. The length method returns the number of elements, and head and last methods refer to the first and last elements, respectively:

Scala
1@main def run: Unit = 2 val numbers = List(1, 2, 3, 4, 5) 3 println(numbers.length) // Size of the list, prints 5 4 5 val colors = List("Red", "Green", "Blue") 6 println(colors.head) // First element, prints "Red" 7 println(colors.last) // Last element, prints "Blue"

Additionally, the size method also returns the number of elements in the list, similar to length. The isEmpty method checks if the list is empty, returning true if it is and false otherwise. The contains method checks if a certain element exists in the list:

Scala
1@main def run: Unit = 2 val items = List("Pen", "Book", "Notebook") 3 println(items.size) // 3 4 println(items.isEmpty) // false 5 println(items.contains("Book")) // true 6 println(items.contains("Pencil")) // false
Difference between Arrays and Lists

In Scala, both arrays and lists are used to store collections of elements, but they serve different purposes and have different characteristics.

  1. Mutability:

    • Arrays: Arrays are mutable, meaning you can change their elements after creation. However, their size is fixed upon creation and cannot be changed.
    • Lists: By default, lists in Scala are immutable. You cannot change their elements or size once created, although you can create new lists based on existing ones. Mutable lists are available via ListBuffer.
  2. Performance:

    • Arrays: Arrays offer fast access to any element because they store elements in contiguous memory locations.
    • Lists: Lists offer fast access to the first element but can be slower to access other elements because each element points to the next one, forming a chain.
  3. Usage:

    • Arrays: Use arrays when you need quick access to elements and the size of the collection is fixed. Arrays are suitable for performance-critical tasks where elements need to be frequently updated but the number of elements remains the same.
    • Lists: Use lists when you need to frequently add or remove elements and want an easy way to manage collections without modifying the original structure. Lists are suitable for scenarios where you benefit from immutability or when the collection size may change. For a dynamic, mutable list, consider using ListBuffer.

Understanding the difference between arrays and lists will help you choose the appropriate data structure based on your needs.

Quick Lesson Summary and Upcoming Practice

Congratulations! You've unravelled Lists in Scala today, uncovering their essence, learning how to create and manipulate them, and understanding their properties. Next, we will put these knowledge points into practice. The upcoming practice will help you cement these concepts and refine your programming skills further. See you soon in the exciting world of Scala!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.