View Source Loops

You can iterate over lists, tuples, keyword lists, and maps in a few different ways. Here are the most common ones:

The for/1 Comprehension

# You can iterate over a range ascending
result = for idx <- 1..10//1, do: idx
IO.inspect(result, label: "range - asc")

# Or descending. Note the step of -2.
# If you don't set the step, the loop will stop after the first element.
result = for idx <- 10..1//-2, do: idx
IO.inspect(result, label: "range - desc")

# You can iterate through a list of elements
result = for el <- ["Peter", 32, 190.47, :active], do: el
IO.inspect(result, label: "elements")

# Or you can have a nested for-loop
result = for x <- [1, 2], y <- [4, 5], do: [x: x, y: y]
IO.inspect(result, label: "nested")
range - asc: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
range - desc: [10, 8, 6, 4, 2]
elements: ["Peter", 32, 190.47, :active]
nested: [[x: 1, y: 4], [x: 1, y: 5], [x: 2, y: 4], [x: 2, y: 5]]

Enum helpers

You will mostly use the Enum helper functions to iterate and modify collections. Here are the most used ones:

# Apply a function to every element and return the result.
Enum.map([1, 2, 3], fn x -> x * 2 end)
# => [2, 4, 6]

# Apply a function, but ignore the result.
Enum.each([1, 2, 3], fn x -> x * 2 end)
# => :ok

# Apply a function and add the result to an accumulator.
Enum.reduce([1, 2, 3], 0, fn x, acc -> acc + x end)
# => 6

# Only keep the elements for which the function evaluates to truthy and filter out the rest.
Enum.filter([1, 2, 3], fn x -> x == 2 end)
# => [2]

# Reject/remove an element if the function evaluates to truthy.
Enum.reject([1, 2, 3], fn x -> x == 2 end)
# => [1, 3]

Recursive Functions

A common pattern in functional programming is to have recursive loops using function clauses. Elixir uses tail call optimisation to keep the memory overhead low and to avoid stack overflows.

defmodule RunElixir.Loop do
  def loop(collection, fun), do: do_loop(collection, [], fun)

  # Applies an anonymous function to each element and returns the result as list.
  defp do_loop([], result, _fun), do: Enum.reverse(result)
  defp do_loop([value | rest], result, fun), do: do_loop(rest, [fun.(value) | result], fun)
end

RunElixir.Loop.loop([1, 2, 3], &(&1 * 2))
# => [2, 4, 6]

Our loop/2 function executes the do_loop/3 private function which calls itself recursively until it has traveresed the entire list. With every call, the second clause of do_loop/3 removes one element from the list, applies the anonymous function to it, and adds the result to the results list. When the list of elements is exhausted, the first do_loop/3 clause matches. It reverses the results and returns them.