← All series

Series contents

Log in to track your progress

  1. 1. Welcome to Alchemist Camp Episode
  2. 2. Lesson 1: The guessing game Episode
  3. 3. Solution 1: The Greeter Episode
  4. 4. Lesson 2: Word Count Episode
  5. 5. Word Count ULTIMATE EDITION! Episode
  6. 6. Minimal Todo List Part 1 Episode
  7. 7. Elixir lists vs Elixir tuples Article
  8. 8. The Image Snatcher Episode
  9. 9. Minimal Todo List Part 2 Episode
  10. 10. Elixir maps made effortless Article
  11. 11. Fibonacci with tail recursion Episode
  12. 12. Mini Markdown Episode
  13. 13. Extending Mini Markdown Episode
  14. 14. Alchemy Markdown Episode
  15. 15. Using mix to modularize and add tests Episode
  16. 16. Command line applications with escript Episode
  17. 17. Caboose, a simple Unix tail clone Episode
  18. 18. Game board (Tictac Part 1) Episode
  19. 19. Structs: Maps with checks and default values Article
  20. 20. Deck generation, Pythagorean Triplets and more Episode
  21. 21. Whiteboarding the Tictac state machine Episode
  22. 22. Game state machine (Tictac Part 2) Episode
  23. 23. Modelling the memory game Episode
  24. 24. Finishing Tictac and making a CLI Episode
  25. 25. Threatened by rooks, bishops and knights Episode
  26. 26. A worker to log stats from a YouTube’s API Episode
  27. 27. Constructing bitmap files with Elixir Episode
  28. 28. Making bitmaps with color palettes Episode
  29. 29. Flattening lists recursively in Elixir Episode

Elixir lists vs Elixir tuples

Along with maps, Lists and Tuples are both ubiquitous and somewhat surprising for Elixir learners. Here's a quick guide.

Lists are linked lists

Elixir lists look just like arrays from C, Java or JavaScript, but they're not. They're not laid out contiguously in memory. They're a series of nodes where each node holds a piece of data and a pointer to the next node. The final node points to nothing.

This has performance implications. In order to read the final element in a list, you must traverse every element from the head to the tail of the list! Prepending an element to the front of the list is cheap, O(1), but accessing an element at the end is O(n)

Tuples are more like Arrays

Elixir tuples are stored contiguously in memory. Accessing any element is O(1). On the down-side, inserting or deleting an element involves copying the entire tuple, which is O(n). Remember, like everything else in the language, Tuples are immutable!

List elements are usually of the same type

This is more of a convention than a rule. Since lists implement the Enumerable protocol and it's very common to use functions like Enum.map, Enum.reduce and Enum.each that pass each element into a function, life is easier if everything in the list has the same shape.

Tuples, on the other hand, are very often mixed types. They're commonly returned from functions and pattern matched against and in this case the first element is usually a status. For example:

case retrieve_stuff do
  {:ok, stuff} -> process(stuff)
  {:err, msg} -> Logger.error("Error with message: %{msg}")
end

Converting lists and tuples is easy

You can convert a list to a tuple with List.to_tuple(some_list) and you can convert a tuple to a list with Tuple.to_list(some_tuple). For example:

my_list = [1, 2, 3]
my_tuple = {:a, :b, :c}

other_tuple = List.to_tuple(my_list)   # equals {1, 2, 3}
other_list = Tuple.to_list(my_tuple)   # equals [:a, :b, :c]

Common questions

How do I get the nth element of a list?
Use Enum.at/2. For example, Enum.at([1, 2, 3, 4], 2) will return 3 since lists are zero-indexed.

How do I get the nth element of a tuple?
Use Kernel.elem/2. For example, elem({:a, :b, :c}, 0) will return :a since tuples are also zero-indexed.

How do I insert an element into a list?
Use List.insert_at/3. For example, List.insert_at([:foo, :bar, :baz], 1, :yolo) returns [:foo, :yolo, :bar, :baz].

You can delete elements in the same way with List.delete_at/2.

If you're prepending to the beginning of a list (which is very performant), then you can also use a cons syntax and insert an element like this:

my_list = [1, 2, 3]
[:hello | my_list]  # returns [:hello, 1, 2, 3]

How do I insert an element into a tuple?
Use Tuple.insert_at/3. For example, Tuple.insert_at({:ok, :stuff}, 1, :yolo) returns {:ok, :yolo, :stuff}.

You can delete elements in the same way with Tuple.delete_at/2.

How do I get the length of a list or a tuple?
Use Kernel.tuple_size/1 for tuples and use Enum.count/1 for lists.

What's a good reference if I need to know more?
It's best to go straight to the official docs!

Open standalone page ↗

No Comments