Part 1
Part 2
Slicing and Dicing with Enum in Elixir
A 10-Pack of Bears 🐻
Here’s the list of bears we used in the video:
def list_bears do
[
%Bear{id: 1, name: "Teddy", type: "Brown", hibernating: true},
%Bear{id: 2, name: "Smokey", type: "Black"},
%Bear{id: 3, name: "Paddington", type: "Brown"},
%Bear{id: 4, name: "Scarface", type: "Grizzly", hibernating: true},
%Bear{id: 5, name: "Snow", type: "Polar"},
%Bear{id: 6, name: "Brutus", type: "Grizzly"},
%Bear{id: 7, name: "Rosie", type: "Black", hibernating: true},
%Bear{id: 8, name: "Roscoe", type: "Panda"},
%Bear{id: 9, name: "Iceman", type: "Polar", hibernating: true},
%Bear{id: 10, name: "Kenai", type: "Grizzly"}
]
endAs always, feel free to use whatever type of data you like. The actual content isn’t important!
Exercise: Delegate DELETE to a Controller Action
In a previous exercise, you defined a route that handles a DELETE request. Now, change that route to delegate to a new function/action in the BearController.
Solution:
# in handler.ex
def route(%{method: "DELETE", path: "/bears/" <> _id} = conv) do
BearController.delete(conv, conv.params)
end
# in bear_controller.ex
def delete(conv, _params) do
%{ conv | status: 403, resp_body: "Deleting a bear is forbidden!"}
endCapturing Expressions
In the video, we used the & operator to capture named functions. For example, we captured the String.upcase function:
iex> phrases = ["lions", "tigers", "bears", "oh my"]
iex> Enum.map(phrases, &String.upcase(&1))
["LIONS", "TIGERS", "BEARS", "OH MY"]The & capture operator creates an anonymous function that calls String.upcase. The &1 is a placeholder for the first argument passed to the function. It’s shorthand for:
iex> Enum.map(phrases, fn(x) -> String.upcase(x) end)You can also capture expressions using the & operator. For example, to triple a list of numbers by calling map with a list and an anonymous “tripler” function:
iex> Enum.map([1, 2, 3], fn(x) -> x * 3 end)
[3, 6, 9]Here’s the shorthand way using the & capture operator:
iex> Enum.map([1, 2, 3], &(&1 * 3))
[3, 6, 9]You can also bind the anonymous function to a variable:
iex> triple = &(&1 * 3)
#Function<6.118419387/1 in :erl_eval.expr/5>
> Enum.map([1, 2, 3], triple)
[3, 6, 9]Exercise: Capture Functions
For extra practice, write an anonymous function that adds two numbers and call it.
iex> add = fn(a,b) -> a + b end
iex> add.(1, 2)
3iex> add = &(&1 + &2)
iex> add.(3, 5)
8Then, write a shorthand version using the & capture operator. Next, look up the documentation for String.duplicate and try capturing it in two ways.
Exercise: Implement my_map
In a previous exercise, you used recursion to triple numbers in a list. Now, you can generalize that idea using Enum.map:
iex> nums = [1, 2, 3, 4, 5]
iex> Enum.map(nums, &(&1 * 2))
[2, 4, 6, 8, 10]
iex> Enum.map(nums, &(&1 * 4))
[4, 8, 12, 16, 20]
iex> Enum.map(nums, &(&1 * 5))
[5, 10, 15, 20, 25]Now, try implementing your own version of map to validate what you’ve learned:
Solution:
defmodule Recurse do
def my_map([head | tail], fun) do
[fun.(head) | my_map(tail, fun)]
end
def my_map([], _fun), do: []
end
IO.inspect Recurse.my_map([1, 2, 3, 4, 5], &(&1 * 2))Exercise: Reduce the Headers
In a previous video, we parsed request headers using recursion. Now, refactor that function using Enum.reduce:
Solution:
def parse_headers(header_lines) do
Enum.reduce(header_lines, %{}, fn(line, headers_so_far) ->
[key, value] = String.split(line, ": ")
Map.put(headers_so_far, key, value)
end)
endThis reduces the list of headers into a single map of key-value pairs, which simplifies the previous recursive implementation.
Code So Far
The code for this section is in the enum directory found within the video-code directory of the code bundle
Why always me?