Reading — step 1 of 5
Learn
~1 min readPattern Matching and Pipelines
Enum is eager. Stream is lazy. Same operations, very different performance characteristics on big data.
Enum — materializes intermediate lists:
1..1_000_000
|> Enum.map(&(&1 * 2)) # builds full list of 1M doubled
|> Enum.filter(&rem(&1, 3) == 0) # builds list of those % 3 == 0
|> Enum.take(5) # finally takes 5
Every Enum.something/2 allocates a new list. For 1M items, that's 1M doubled, then filtered to ~330K, then sliced to 5. Wasteful.
Stream — lazy:
1..1_000_000
|> Stream.map(&(&1 * 2))
|> Stream.filter(&rem(&1, 3) == 0)
|> Enum.take(5) # `Enum.take` is the consumer that triggers evaluation
Nothing runs until Enum.take (or Enum.to_list, Enum.reduce, etc.). The pipeline only computes 5 results — short-circuits as soon as 5 are accumulated.
Most-used Enum functions:
Enum.map([1,2,3], &(&1 * 2)) # [2, 4, 6]
Enum.filter([1,2,3,4], &rem(&1, 2) == 0) # [2, 4]
Enum.reduce([1,2,3], 0, &+/2) # 6
Enum.sort([3,1,2]) # [1, 2, 3]
Enum.sort_by(users, & &1.age)
Enum.group_by([1,2,3,4], &rem(&1, 2)) # %{0 => [2,4], 1 => [1,3]}
Enum.chunk_every([1,2,3,4,5], 2) # [[1,2], [3,4], [5]]
Enum.zip([1,2,3], ["a","b","c"]) # [{1,"a"}, {2,"b"}, {3,"c"}]
Enum.with_index(["a","b","c"]) # [{"a",0}, {"b",1}, {"c",2}]
For most everyday code, Enum is fine — lists are short. Reach for Stream when:
- Working with big collections
- Building infinite sequences
- Reading line-by-line from a file:
File.stream!("big.log")
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…