Enum and Stream

Elixir Enum and Stream functions for iterating, mapping, filtering, and reducing collections

The Enum module works on eager collections (lists, maps, ranges, etc.). Stream provides lazy operations that compute only when needed.

Enum — most used functions

Iteration

Function Example Result
Enum.each/2 Enum.each([1,2,3], &IO.puts/1) :ok (side effect)
Enum.map/2 Enum.map([1,2,3], &(&1 * 2)) [2, 4, 6]
Enum.filter/2 Enum.filter(1..5, &rem(&1,2)==0) [2, 4]
Enum.reject/2 Enum.reject(1..5, &rem(&1,2)==0) [1, 3, 5]
Enum.reduce/3 Enum.reduce([1,2,3], 0, &+/2) 6
Enum.reduce/2 Enum.reduce([1,2,3], &+/2) 6 (first elem is acc)

Finding & testing

Function Example Result
Enum.find/3 Enum.find([1,2,3], &(&1 > 2)) 3
Enum.find_value/3 Enum.find_value([1,2,3], &(&1 > 2 && &1)) 3
Enum.any?/2 Enum.any?([1,2,3], &(&1 > 2)) true
Enum.all?/2 Enum.all?([1,2,3], &(&1 > 0)) true
Enum.member?/2 Enum.member?([1,2,3], 2) true
Enum.empty?/1 Enum.empty?([]) true
Enum.count/1 Enum.count([1,2,3]) 3
Enum.count/2 Enum.count([1,2,3], &(&1 > 1)) 2

Sorting & grouping

Function Example Result
Enum.sort/1 Enum.sort([3,1,2]) [1, 2, 3]
Enum.sort/2 Enum.sort([3,1,2], :desc) [3, 2, 1]
Enum.sort_by/2 Enum.sort_by([~D[2023-01-01], ~D[2022-01-01]], & &1) sorted by date
Enum.group_by/2 Enum.group_by([1,2,3], &rem(&1,2)) %{1 => [1, 3], 0 => [2]}
Enum.uniq/1 Enum.uniq([1,1,2,2,3]) [1, 2, 3]
Enum.uniq_by/2 Enum.uniq_by([1,2,3,4], &rem(&1,2)) [1, 2]

Slicing & chunking

Function Example Result
Enum.take/2 Enum.take([1,2,3,4,5], 2) [1, 2]
Enum.drop/2 Enum.drop([1,2,3,4,5], 2) [3, 4, 5]
Enum.take_while/2 Enum.take_while([1,2,3], &(&1 < 3)) [1, 2]
Enum.drop_while/2 Enum.drop_while([1,2,3], &(&1 < 3)) [3]
Enum.slice/2 Enum.slice([1,2,3,4,5], 1..3) [2, 3, 4]
Enum.chunk_every/2 Enum.chunk_every([1,2,3,4,5], 2) [[1,2],[3,4],[5]]
Enum.chunk_by/2 Enum.chunk_by([1,1,2,2,1], &(&1)) [[1,1],[2,2],[1]]

Concat & flatten

Function Example Result
Enum.concat/1 Enum.concat([[1,2],[3,4]]) [1, 2, 3, 4]
Enum.concat/2 Enum.concat([1,2], [3,4]) [1, 2, 3, 4]
Enum.flat_map/2 Enum.flat_map([1,2], &[&1, &1*10]) [1, 10, 2, 20]

Conversions

Function Example Result
Enum.to_list/1 Enum.to_list(1..3) [1, 2, 3]
Enum.join/2 Enum.join([1,2,3], ", ") "1, 2, 3"
Enum.into/2 Enum.into([a: 1], %{}) %{a: 1}
Enum.into/3 Enum.into([1,2], [], &(&1 * 2)) [2, 4]

Zip & with_index

Function Example Result
Enum.zip/2 Enum.zip([:a,:b], [1,2]) [{:a, 1}, {:b, 2}]
Enum.with_index/1 Enum.with_index([:a,:b]) [{:a, 0}, {:b, 1}]

Comprehensions

# Basic
for n <- [1, 2, 3], do: n * n       # => [1, 4, 9]

# With filter
for n <- 1..10, rem(n, 2) == 0, do: n  # => [2, 4, 6, 8, 10]

# With multiple generators
for x <- [1, 2], y <- [:a, :b], do: {x, y}
# => [{1, :a}, {1, :b}, {2, :a}, {2, :b}]

# Into a map
for {k, v} <- %{a: 1, b: 2}, into: %{}, do: {k, v * 2}
# => %{a: 2, b: 4}

# Uniq option
for n <- [1, 1, 2, 2, 3], uniq: true, do: n  # => [1, 2, 3]

Stream — lazy operations

Streams evaluate elements only as needed. Use them for large or infinite collections.

# Creating streams
1..1_000_000 |> Stream.map(&(&1 * 2)) |> Stream.filter(&rem(&1, 3) == 0) |> Enum.take(5)
# => [6, 12, 18, 24, 30]

# Stream.cycle — infinite repetition
Stream.cycle([1, 2, 3]) |> Enum.take(7)  # => [1, 2, 3, 1, 2, 3, 1]

# Stream.unfold — generate from state
Stream.unfold(1, fn n -> {n, n + 1} end) |> Enum.take(5)  # => [1, 2, 3, 4, 5]

# Stream.iterate — infinite sequence
Stream.iterate(1, &(&1 * 2)) |> Enum.take(5)  # => [1, 2, 4, 8, 16]

# File lines (lazy)
File.stream!("log.txt") |> Stream.map(&String.trim/1) |> Enum.take(10)

When to use Stream: When working with large collections, infinite sequences, or when you want to chain multiple operations without creating intermediate lists.