sábado, 1 de abril de 2017

Empezando con Elixir 3

Enum


Enum es un conjunto de funciones para interactuar con colecciones. El cual incluya más de 100 funciones.

Si queremos enumerar todas las funciones podemos hacer lo siguiente:

iex(1)> Enum.__info__(:functions) |> Enum.each(fn({function, arity}) -> IO.puts "#{function}/#{arity}" end)
all?/1
all?/2
any?/1
any?/2
at/2
at/3
chunk/2
...

Usando esto, está claro que tenemos una gran cantidad de funcionalidad, y eso es por una razón clara. La enumeración es el núcleo de la programación funcional y es una cosa increíblemente útil.

Veamos algunas funciones importantes : 

all? Nos permite saber si todos los elementos de una lista cumplen alguna condición, veamos un ejemplo: 

iex> Enum.all?(["foo", "bar", "hello"], fn(s) -> String.length(s) == 3 end)
false

iex> Enum.all?(["foo", "bar", "hello"], fn(s) -> String.length(s) > 1 end)
true

any? Parecido a all? pero retorna true si alguno cumple la condición:

iex> Enum.any?(["foo", "bar", "hello"], fn(s) -> String.length(s) == 5 end)
true

iex> Enum.any?(["foo", "bar"], fn(s) -> String.length(s) == 5 end)        
false

chunk, dada una colección retorna un grupo de colecciones con la cantidad de elementos pasada como segundo parámetro. 

iex> Enum.chunk([1, 2, 3, 4, 5, 6], 2)
[[1, 2], [3, 4], [5, 6]]

chunk_by igual que chunk pero se dividen las listas a partir de una función. 

iex> Enum.chunk_by(["one", "two", "three", "four", "five"], fn(x) -> String.length(x) end)
[["one", "two"], ["three"], ["four", "five"]]

iex> Enum.chunk_by(["one", "two", "three", "four", "five", "six"], fn(x) -> String.length(x) end)
[["one", "two"], ["three"], ["four", "five"], ["six"]]

map_every a veces fragmentar una colección no es suficiente para exactamente lo que pueda necesitar. En este es el caso, map_every puede ser muy útil para modificar sólo los elementos específicos:

iex> Enum.map_every([1, 2, 3, 4], 2, fn x -> x * 2 end)
[2, 2, 6, 4]

each necesitamos iterar toda la colección: 

iex> Enum.each(["one", "two", "three"], fn(s) -> IO.puts(s) end)
one
two
three

each retorno al atom :ok

map, aplica una función a una collección retornando una segunda colección: 

iex> Enum.map([0, 1, 2, 3], fn(x) -> x - 1 end)
[-1, 0, 1, 2]

min y max, se puede suponer que buscan el minimo y el maximo: 

iex> Enum.min([5, 3, 0, -1])
-1
iex> Enum.max([5, 3, 0, -1])
5

reduce podemos destilar nuestra colección en un solo valor. Para ello, suministramos un acumulador opcional para pasar a nuestra función; Si no se proporciona ningún acumulador, se utiliza el primer valor:

iex> Enum.reduce([1, 2, 3], 10, fn(x, acc) -> x + acc end)
16

iex> Enum.reduce([1, 2, 3], fn(x, acc) -> x + acc end)
6

iex> Enum.reduce(["a","b","c"], "1", fn(x,acc)-> x <> acc end)
"cba1"

sort, ordena una colección : 

iex> Enum.sort([5, 6, 1, 3, -1, 4])
[-1, 1, 3, 4, 5, 6]

iex> Enum.sort([:foo, "bar", Enum, -1, 4])
[-1, 4, Enum, :foo, "bar"]

opcionalmente podemos pasar por parámetro una función: 

# with our function
iex> Enum.sort([%{:val => 4}, %{:val => 1}], fn(x, y) -> x[:val] > y[:val] end)
[%{val: 4}, %{val: 1}]

# without
iex> Enum.sort([%{:count => 4}, %{:count => 1}])
[%{count: 1}, %{count: 4}]

uniq_by, remueve los duplicados: 

iex> Enum.uniq_by([1, 2, 3, 2, 1, 1, 1, 1, 1], fn x -> x end)
[1, 2, 3]