# Working with Elixir Enum and Stream Modules

Note: this page has been created with the use of AI. Please take caution, and note that the content of this page does not necessarily reflect the opinion of Cratecode.

Elixir, a powerful and fun programming language, makes data manipulation feel like a breeze with its Enum and Stream modules. These modules are packed with powerful functions that allow you to work with enumerable data types, like lists and maps, in a more efficient manner. So, let's dive into these fantastic tools and see what they have to offer!

## Elixir Enum Module

The Enum module provides a plethora of functions to work with enumerables, a collection of items that can be traversed, counted, and transformed. Lists, maps, and ranges are examples of enumerable data types in Elixir.

Let's take a look at some of the most useful functions provided by the Enum module:

### map/2

`map/2` applies a given function to each element of an enumerable and returns a new enumerable with the results. Let's see `map/2` in action:

``````squared_numbers = Enum.map([1, 2, 3, 4], fn x -> x * x end)
IO.inspect squared_numbers  # Output: [1, 4, 9, 16]``````

### filter/2

`filter/2` filters elements from an enumerable based on a given condition (predicate function). The function should return `true` or `false` for each element:

``````even_numbers = Enum.filter([1, 2, 3, 4], fn x -> rem(x, 2) == 0 end)
IO.inspect even_numbers  # Output: [2, 4]``````

### reduce/3

`reduce/3` is an incredibly versatile function that can be used to traverse an enumerable and accumulate a result. It accepts an initial accumulator value and a function that takes two arguments: the accumulator and an element of the enumerable. The function should return a new accumulator value.

``````sum = Enum.reduce([1, 2, 3, 4], 0, fn x, acc -> x + acc end)
IO.inspect sum  # Output: 10``````

## Elixir Stream Module

While the Enum module is excellent for eager data manipulation, Elixir's Stream module enables lazy data manipulation. Being lazy means that operations are not executed until the results are explicitly requested (e.g., by converting the stream to a list). This makes Stream particularly useful for working with large or infinite data sets.

Here are some Stream functions that mirror those we've seen in Enum:

### map/2

`Stream.map/2` works similarly to `Enum.map/2`, but it returns a stream instead of an enumerable.

``````squared_numbers = Stream.map([1, 2, 3, 4], fn x -> x * x end)
IO.inspect squared_numbers  # Output: #Stream<[. . .]>``````

To retrieve the results from the stream, we can use `Enum.to_list/1`:

``IO.inspect Enum.to_list(squared_numbers)  # Output: [1, 4, 9, 16]``

### filter/2

`Stream.filter/2` mirrors `Enum.filter/2`, but again, returns a stream:

``````even_numbers = Stream.filter([1, 2, 3, 4], fn x -> rem(x, 2) == 0 end)
IO.inspect even_numbers  # Output: #Stream<[. . .]>
IO.inspect Enum.to_list(even_numbers)  # Output: [2, 4]``````

## Using Enum and Stream Together

You can combine Enum and Stream functions to take advantage of the strengths of each module. For example, we can use Stream to create an infinite sequence of squared numbers and then use Enum to take the first ten numbers from the sequence:

``````squared_numbers = Stream.iterate(1, &(&1 + 1))
|> Stream.map(fn x -> x * x end)
|> Enum.take(10)

IO.inspect squared_numbers  # Output: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]``````

Now that you've got a taste of the power and flexibility offered by Elixir's Enum and Stream modules, you're ready to tackle data manipulation tasks with ease. Happy coding!

Hey there! Want to learn more? Cratecode is an online learning platform that lets you forge your own path. Click here to check out a lesson: Rust Enums (psst, it's free!).