Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Lists

reading/lists.livemd

Lists

Mix.install([
  {:jason, "~> 1.4"},
  {:kino, "~> 0.9", override: true},
  {:youtube, github: "brooklinjazz/youtube"},
  {:hidden_cell, github: "brooklinjazz/hidden_cell"}
])

Navigation

Home Report An Issue TuplesKeyword Lists

Review Questions

Upon completing this lesson, a student should be able to answer the following questions.

  • What is a list, and what is the difference between a list and a tuple?
  • How do you pattern match on a list?

Lists

Lists store a list of other data types. Data types within a list are called elements.

flowchart
  subgraph List
    a[Element] --> b[Element] --> c[Element] --> d[Element]
  end

Use square brackets [] to create a list, and then separate each value with a comma ,.

[1, 2, 3]

Lists can contain any other Elixir term, even other lists.

["a", 2, "c", []]

Lists are used to represent a collection of information. For example, a shopping list, a to-do list, or a list of tags on an article.

Indexes

An index is the position of an element in a list.

In programming, we count indexes starting at 0. Why? The short answer is, it relates to how computer hardware works.

So take this example list.

["a", "b", "c"]
  • "a" is at index 0
  • "b" is at index 1
  • "c" is at index 2
flowchart
  subgraph Index
    0 --> 1 --> 2
  end
  subgraph Elements
    a --> b --> c
  end

Your Turn

In the Elixir cell below, Create a list of your favourite foods as strings.

List Operators

List operators allow us to manipulate lists. Lists can be added together with ++ and subtracted from each other with --.

[1] ++ [2]
[1, 2, 3] -- [2, 3]

Subtraction operations remove the leftmost elements first.

[3, 2, 4, 3, 2] -- [3, 2]

List operations occur from right to left unlike Arithmetic Operators, which can cause some unintuitive behavior. You might think the following operation should result in an empty list [], but instead it returns [2].

[1, 2] -- [1] -- [2]

That’s because [1] -- [2] evaluates first, because the operations occur from right to left.

step1 = [1] -- [2]
result = [1, 2] -- step1

To avoid writing unintuitive code, you can either use brackets or split values in to variables to break up the operations into steps using the match operator.

([1, 2] -- [1]) -- [2]

Your Turn

In the Elixir cell below, add [1, 2, 3] and [4, 5, 6] together to make [1, 2, 3, 4, 5, 6].

In the Elixir cell below, remove [1] from [1, 1, 2, 3] to make [1, 2, 3]

Head And Tail

Under the hood, lists are implemented as linked lists where every element is a cons cell with a head and a tail.

Let’s take the example list [2, 3].

This is actually a linked list made of two cons cells [2 | tail] and [3 | tail].

We can see that [2, 3] is actually syntax sugar for [2 | [3 | []]] which uses a pipe symbol syntax | to join them.

[2 | [3 | []]]

We won’t often write lists this way, but it’s useful to be aware of their internal implementation details for the sake of prepending elements to a list and for pattern matching on a list.

Prepending

Because lists are actually just cons cells joined together, we can prepend elements to a list using [element | list] syntax.

For example, we can prepend 1 to the list [2, 3] to make [1, 2, 3]

flowchart
  1 --> l[2, 3]
[1 | [2, 3]]

You can use a variable in place of a hard-coded list.

list = [2, 3]
[1 | list]

Your Turn

In the Elixir cell below, prepend "hello" to the list ["world"] to make ["hello", "world"]

Pattern Matching Lists

We can pattern match on lists to bind elements in the list to variables.

[one, two] = [1, 2]

This poses an issue for lists though who seem to require a match for every element.

[one] = [1, 2]

To get around this, you can use the [head | tail] syntax for prepending elements to a list.

flowchart LR
  subgraph Head
  L
  end
  subgraph Tail
  I
  S
  T
  end
  L -- tail --> I --> S --> T

The head is the first element of the list.

[head | _tail] = [1, 2, 3, 4, 5, 6, 7]
head

The tail is rest of the elements in the list.

[_head | tail] = [1, 2, 3, 4, 5, 6, 7]
tail

You can access multiple elements at the start of the list separated by commas ,.

[one, two | _tail] = [1, 2, 3, 4, 5, 6, 7]
{one, two}

Your Turn

Bind 1 in the following list to a variable a using pattern matching.

Example solution

[a, _b, _c] = [1, 2, 3]

Enter your solution below.

[1, 2, 3]

Bind 1 in the following list to a variable a using pattern matching.

Example solution

[a | _tail] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

Enter your solution below.

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

Bind 1 and 2, and 3 in the following list to variables a, b, and c using pattern matching.

Example solution

[a, b, c | _tail] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

Enter your solution below.

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

Further Reading

Consider the following resource(s) to deepen your understanding of the topic.

Commit Your Progress

DockYard Academy now recommends you use the latest Release rather than forking or cloning our repository.

Run git status to ensure there are no undesirable changes. Then run the following in your command line from the curriculum folder to commit your progress.

$ git add .
$ git commit -m "finish Lists reading"
$ git push

We’re proud to offer our open-source curriculum free of charge for anyone to learn from at their own pace.

We also offer a paid course where you can learn from an instructor alongside a cohort of your peers. We will accept applications for the June-August 2023 cohort soon.

Navigation

Home Report An Issue TuplesKeyword Lists