Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Data Structures  ›  Lesson

List and Seq

List 14 minA List is an immutable, ordered sequence that is fast to add to at the front and to walk from start to end; Seq is the general type for any ordered sequence, and the type in square brackets says what it holds.

List and Seq

Asha logs four runs this week, and the logbook needs to keep them in order. Scala's workhorse for an ordered group of values is List, and knowing what it does quickly, and what it does slowly, shapes how you use it.

The rule

A List never changes: add at the front, walk from the start.

val runs: List[Double] = List(5.0, 8.5, 3.2, 10.0)

runs.head      // 5.0, the first element
runs.tail      // List(8.5, 3.2, 10.0), everything after the head
runs(1)        // 8.5: positions count from 0
runs.length    // 4
runs.sum       // 26.7

The type parameter. List[Double] reads "a list of Doubles". The type in square brackets is a type parameter: List works for any element type, and the brackets say which one this list holds. List[String] holds text. Scala usually infers it, so List(5.0, 8.5) is already a List[Double].

Immutable. A List cannot be changed. Operations that look like changes return a new list and leave the original alone:

val withMonday = 6.0 :: runs    // List(6.0, 5.0, 8.5, 3.2, 10.0)
val withSunday = runs :+ 7.0    // List(5.0, 8.5, 3.2, 10.0, 7.0)
runs.length                     // still 4

A List is a chain in which each element points to the rest. Adding at the front with :: makes one new link pointing at the old chain, so it is fast whatever the length. Adding at the end with :+, or reading runs(1000), has to walk the chain from the start.

Nil is the empty list, and List.empty[Double] is an empty list of Doubles. Asking an empty list for its head throws NoSuchElementException; headOption returns None instead. Asking for a position past the end, like runs(10), throws IndexOutOfBoundsException.

Seq is the general type for any ordered sequence. A List is a Seq, and so is a Vector. Writing Seq(5.0, 8.5) gives you a List behind the scenes. A function that only needs "some ordered values" should accept a Seq, so callers can pass whichever kind they have.

The shortcut

Ask "which end am I working at?" Adding at the front, or walking from start to finish: a List is ideal. Frequent reads or updates in the middle: reach for a Vector, the next lesson.

Adding Tuesday's run to the frontStep 1 of 4
  1. Start

    runs holds four runs.

Drills

Answer fast — trust the rule.

quick drill

With runs = List(5.0, 8.5, 3.2, 10.0), what is runs(1)?

quick drill

After val more = 6.0 :: runs, what is runs.length?

quick drill

In List[String], what is [String]?

quick drill

What does List.empty[Double].head do?

quick drill

Which operation stays fast on a List of a million runs?

Remember

  • A List is immutable and ordered; the brackets in List[Double] hold its type parameter.
  • Ask which end you work at: the front and start-to-finish walks suit a List; accept a Seq when any ordered values will do.
  • Trap: expecting :: or :+ to change the original, and calling head on an empty list.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainGrowing an immutable list

Asha's runs are List(5.0, 8.5, 3.2, 10.0). Explain what 6.0 :: runs and runs :+ 7.0 each produce, what happens to runs itself, why one of them is faster on a long list, and what List[Double] tells you.