Elixir Cheatsheet
Collections and Enum
Use this Elixir reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Lists
list = [1, 2, 3] [0 | list] # [0, 1, 2, 3] — prepend, O(1) list ++ [4, 5] # append, O(length(left)) list -- [2] # remove first matching 2 hd(list) # 1 tl(list) # [2, 3] length(list) # 3 — O(n) Enum.at(list, 1) # 2 — O(n), lists are not arrays List.first(list); List.last(list) List.flatten([1, [2, [3]]]) # [1, 2, 3]
Lists are linked lists. Prepending is cheap; indexing and appending walk the list.
Tuples
point = {:point, 3, 4}
elem(point, 1) # 3 — O(1) access
put_elem(point, 2, 5) # {:point, 3, 5}
tuple_size(point) # 3Tuples are fixed-size and used for tagged results: {:ok, value} and {:error, reason}.
Keyword Lists
opts = [limit: 10, sort: :asc] # sugar for [{:limit, 10}, {:sort, :asc}] opts[:limit] # 10; nil if missing Keyword.get(opts, :sort, :desc) Keyword.put(opts, :limit, 20) Keyword.fetch!(opts, :limit) # raises if missing Keyword.validate!(opts, limit: 10, sort: :asc) # reject unknown keys Keyword.merge(defaults, overrides) Keyword.has_key?(opts, :sort)
Keyword lists are lists of {atom, value} tuples: ordered, allow duplicate keys, and pattern-match positionally (so prefer Keyword.get/3 over matching). They are the idiomatic options type; use maps for general key-value data.
Ranges
1..5 |> Enum.to_list() # [1, 2, 3, 4, 5] 5..1//-1 |> Enum.to_list() # [5, 4, 3, 2, 1] 1..10//2 |> Enum.to_list() # [1, 3, 5, 7, 9] — step syntax n in 1..100 # membership check
Enum Essentials
Enum.map(nums, &(&1 * 2)) Enum.filter(nums, &(rem(&1, 2) == 0)) Enum.reject(nums, &(&1 < 0)) Enum.reduce(nums, 0, fn x, acc -> x + acc end) Enum.sum(nums); Enum.product(nums) Enum.count(nums); Enum.count(nums, &(&1 > 0)) Enum.min(nums); Enum.max(nums); Enum.min_max(nums) Enum.any?(nums, &(&1 > 10)); Enum.all?(nums, &(&1 >= 0)) Enum.find(nums, &(&1 > 10)) # first match or nil Enum.member?(nums, 3) # same as 3 in nums Enum.sort(nums); Enum.sort(nums, :desc) Enum.uniq(nums) Enum.reverse(nums) Enum.take(nums, 3); Enum.drop(nums, 3) Enum.take_while(nums, &(&1 < 5)); Enum.drop_while(nums, &(&1 < 5)) Enum.join(words, ", ")
Enum for Shaping Data
Enum.sort_by(users, & &1.age) # sort by a key Enum.sort_by(users, & &1.age, :desc) Enum.max_by(users, & &1.score) Enum.group_by(words, &String.first/1) # %{"a" => [...], "b" => [...]} Enum.frequencies(["a", "b", "a"]) # %{"a" => 2, "b" => 1} Enum.with_index(["a", "b"]) # [{"a", 0}, {"b", 1}] Enum.zip([1, 2], [:a, :b]) # [{1, :a}, {2, :b}] Enum.unzip([{1, :a}, {2, :b}]) # {[1, 2], [:a, :b]} Enum.chunk_every([1, 2, 3, 4, 5], 2) # [[1, 2], [3, 4], [5]] Enum.chunk_every([1, 2, 3], 2, 1, :discard) # sliding pairs [[1,2],[2,3]] Enum.flat_map(users, & &1.tags) # map + flatten one level Enum.dedup([1, 1, 2, 2, 1]) # [1, 2, 1] — consecutive only Enum.split_with(nums, &(&1 >= 0)) # {matching, rest} Enum.into([{:a, 1}, {:b, 2}], %{}) # %{a: 1, b: 2} Map.new(users, fn u -> {u.id, u} end) # index a list by key Enum.map_join(1..3, "-", &to_string/1) # "1-2-3" Enum.each(items, &IO.puts/1) # side effects, returns :ok Enum.random(1..6); Enum.shuffle(list); Enum.take_random(list, 2)
MapSet
set = MapSet.new([1, 2, 3]) MapSet.put(set, 4) MapSet.delete(set, 1) MapSet.member?(set, 2) # true — O(log n) MapSet.union(a, b); MapSet.intersection(a, b); MapSet.difference(a, b) MapSet.subset?(a, b) MapSet.new([1, 2]) |> Enum.map(&(&1 * 10)) # sets are enumerable
Use MapSet for uniqueness and fast membership; Enum.uniq/1 for one-off dedup of a list.
Pipelines
[1, 2, 3, 4, 5] |> Enum.filter(&(rem(&1, 2) == 1)) |> Enum.map(&(&1 * &1)) |> Enum.sum()
The value on the left becomes the first argument of the call on the right.
Comprehensions
for x <- [1, 2, 3], do: x * x for x <- 1..10, rem(x, 2) == 0, do: x # filter clause for x <- 1..3, y <- 1..3, x < y, do: {x, y} # nested generators for {name, score} <- scores, score >= 90, do: name for word <- words, into: %{}, do: {word, String.length(word)} for <<b <- "abc">>, do: b + 1 # binary generator for x <- 1..5, reduce: 0 do acc -> acc + x end # reduce: option
Streams
1..1_000_000 |> Stream.map(&(&1 * 2)) |> Stream.filter(&(rem(&1, 3) == 0)) |> Enum.take(5) File.stream!("big.log") |> Stream.map(&String.trim/1) |> Enum.count() Stream.iterate(1, &(&1 * 2)) |> Enum.take(8) # infinite sequences Stream.cycle([:a, :b]) |> Enum.take(5)
Stream is lazy: nothing runs until an Enum function consumes it. Use streams for large or infinite input to avoid building intermediate lists.