Elixir Learnings 002: playing around with lists

·

0 min read

This is part of my series on Elixir Learnings, where I share micro-posts about everything I'm learning related to Elixir.

Today we going to play around with lists. At the same time lists are very simple, they are powerful. And we use it always in our day-to-day work. Here we will understand some common concepts we need to handle lists.

Add and remove items

We have two ways to add new items to the list. We can use the insert_at List function and the ++ operator to concat lists.

The insert_at function receives three parameters: the list, the index position you want to add the new item, and the item.

items = [1 ,2 ,3 ,4]
List.insert_at(items, 0, 0) # [0, 1 ,2 ,3 ,4]
List.insert_at(items, 4, 5) # [1 ,2 ,3 ,4, 5]

And Elixir lists are immutable. After these operations, if we call the items again, it will be the first value.

items # [1 ,2 ,3 ,4]

The list value doesn't change.

We can also use the ++ operator to concat lists to add a new item.

brothers = ['TK', 'Yuji', 'Bruno']
new_brother = 'Kaio'
brothers ++ [new_brother] # ['TK', 'Yuji', 'Bruno', 'Kaio']

Not only one item. But concat any list.

['TK', 'Kaio'] ++ ['Yuji', 'Bruno'] # ['TK', 'Kaio', 'Yuji', 'Bruno']

With the -- operator, we can subtract a list of items from the left list.

bookshelf = ['HP', 'Compound Effect', 'Enlightenment Now']
bookshelf -- ['HP'] # ['Compound Effect', 'Enlightenment Now']

Getting items

I learned simple but very useful functions to get items: first and last.

List.first([1, 2, 3]) # 1
List.last([1, 2, 3]) # 3

We can also handle empty lists:

List.first([]) # nil
List.last([]) # nil

Make it flat

Another cool function is flat. It flats nested lists. In other words, it transforms nested lists into just one with all the elements.

  • Not so nested lists
List.flatten([1, [2], [3]]) # [1, 2, 3]
  • More complex nested lists
List.flatten([1, [[2, [3]]]]) # [1, 2, 3]
  • Nested empty lists
List.flatten([[], [[], []]]) # []

Iterate through it

One thing we always do with lists is iteration. We can use the each function from the Enum module to loop through the list.

items = [1, 2, 3, 4, 5]
Enum.each(items, fn (n) -> IO.inspect(n) end)

And we can also use a shortcut for functions.

Enum.each(items, &IO.inspect/1) # shortcut

The Enum module has various other functions to work on data types, like lists, that implements the Enumerable protocol.

Destructuring

Another way to get items from the list is called destructuring. We unpack items from the list by specifying the "variables" inside a list.

[a, b, c] = [1, 2, 3]
IO.inspect a
IO.inspect b
IO.inspect c

With the [a, b, c], we are specifying the variable names to destructure the list.

If you want to get only the second item, use the _ operator (also called wildcard).

[_, x, _] = [1, 2, 3]
IO.inspect x # 2

Another interesting way to get items is by using the | operator. With this operator, we get the head (first item) and the right part represents the other items.

[head | rest] = [1, 2, 3, 4, 5]
IO.inspect head # 1
IO.inspect rest # [2, 3, 4, 5]

But it's not just about the first element. We can specify more than just the first item.

[first, second | rest] = [1, 2, 3, 4, 5]
IO.inspect first # 1
IO.inspect second # 2
IO.inspect rest # [2, 3, 4, 5]

Lists are linked lists in Elixir. The last node points to an empty list.

[head | rest] = [:a]
IO.inspect head # :a
IO.inspect rest # []

This is why when we get the rest, it is an empty list.

Wrapping up

Lists have the wrap function to transform values into a list. It wraps the value in a list.

List.wrap("TK") # ["TK"]
List.wrap(1) # [1]
List.wrap(true) # [true]
List.wrap(:ola) # [:ola]

We can also wrap a list. But it just returns the same list.

List.wrap([1, 2, 3]) # [1, 2, 3]

nil is also a value. It represents the absence of a value. When we wrap it, the function returns an empty list.

List.wrap(nil) # []

Resources