NOTE: `Enum.chunks` has become `Enum.chunk`, and `Enum.chunks_by` has become `Enum.chunk_by`.

Hello again, and welcome to Episode 017: Enum, Part 1. In today's episode, we're going to cover the first part of the Enum module.

• `all?`
• `any?`
• `at`
• `chunks`
• `chunks_by`
• `concat`
• `count`

Let's get started.

## `all?`

`Enum.all?` returns true unless one or more items in the collection return `false` for the provided fun:

``````iex(1)> Enum.all?([1,2,3], fn(x) -> rem(x, 2) == 0 end)
false
iex(2)> Enum.all?([1,2,3], fn(x) -> x > 0 end)
true``````

## `any?`

`Enum.any?` returns true if at least one item in the collection returns `true` for the provided fun:

``````iex(3)> Enum.any?([1,2,3], fn(x) -> rem(x, 2) == 0 end)
true
iex(4)> Enum.any?([1,2,3], fn(x) -> x < 0 end)
false``````

## `at`

`Enum.at` finds the element in the collection at the given index. This is a zero-based index.

``````iex(5)> Enum.at([1,2,3], 1)
2
iex(6)> Enum.at([1,2,3], 4)
nil``````

## `chunks`

`Enum.chunks` returns chunks of the collection. It has a few different ways of being called. The most simple and understandable is `Enum.chunks/2`:

``````iex(10)> Enum.chunks([1,2,3,4], 2)
[[1, 2], [3, 4]]``````

When called with arity 2 (`Enum.chunks(collection, size)`), it returns a collection of lists containing `size` elements each. By default, you're guaranteed to have each item in the list be of size `size`, but that means you might not get every element from the input collection out of it. For instance:

``````iex(10)> Enum.chunks([1,2,3,4,5], 2)
[[1, 2], [3, 4]]``````

Here, `5` is not returned because there aren't enough items in the list to place it into an appropriately-sized chunk.

When called with arity 3 (`Enum.chunks(collection, size, step)`), you can define the step between chunks. With arity 2, `step` is the same as `size`. Here's an example:

``````iex(14)> Enum.chunks([1,2,3,4,5], 3, 2)
[[1, 2, 3], [3, 4, 5]]``````

The final way you can call it is with arity 4 (```Enum.chunks(collection, size, step, padding)```). When called this way, items are taken from `padding` to fill out any gaps to finish up the final chunk:

``````iex(15)> Enum.chunks([1,2,3,4,5], 3, 3, [1])
[[1, 2, 3], [4, 5, 1]]``````

If there aren't enough items in `padding` then the last chunk is returned without the same size as the rest. Here's an example:

``````iex(15)> Enum.chunks([1,2,3,4,5], 3, 3, [])
[[1, 2, 3], [4, 5]]``````

## `chunks_by`

`Enum.chunks_by` splits the input collection at each point where `fun` returns a new value. I'm basically copying the example from the documentation here, because it does a great job of showing this behaviour in a fairly nuanced way:

``````iex(19)> Enum.chunks_by([1, 2, 2, 3, 4, 4, 6, 7, 7], fn(x) -> rem(x, 2) == 1 end)
[[1], [2, 2], [3], [4, 4, 6], [7, 7]]``````

## `concat`

`Enum.concat` concatenates a list of enumerables into a single list:

``````iex(20)> Enum.concat([[1], [2,3], [4]])
[1, 2, 3, 4]``````

All of my examples have focused on lists, but Enum works on anything that implements the Enum protocol - for instance, ranges:

``````iex(21)> Enum.concat([1..2, 3..3])
[1, 2, 3]``````

## `count`

`Enum.count/1` returns the number of items in the input collection:

``````iex(23)> Enum.count([:a, :b])
2``````

With arity 2, it returns the number of items in the input collection for which the fun returns true:

``````iex(24)> Enum.count([:a, 1], fn(x) -> is_integer(x) end)
1``````