Chapter 10
Mix.install([
{:kino, "~> 0.8"}
])
Exercise: ListsAndRecursion-5
defmodule MyEnum do
def all?([]), do: true
def all?([nil | _]), do: false
def all?([h | t]), do: h && all?(t)
def all?([], _), do: true
def all?([h | t], fun), do: fun.(h) && all?(t, fun)
def each([], _), do: :ok
def each([h | t], fun) do
fun.(h)
each(t, fun)
end
def filter([], _), do: []
def filter([h | t], fun) do
if fun.(h) do
[h | filter(t, fun)]
else
filter(t, fun)
end
end
def split(list, count) when count >= 0 do
first = take(list, count)
{first, list -- first}
end
def split(list, count) do
first = take(list, max(0, length(list) + count))
{first, list -- first}
end
def take(_, 0), do: []
def take([], _), do: []
def take([h | t], amount) when amount > 0, do: [h | take(t, amount - 1)]
def take(list, amount), do: _take(list, max(0, length(list) + amount))
defp _take(list, 0), do: list
defp _take([_ | t], amount), do: _take(t, amount - 1)
end
ExUnit.start(auto_run: false)
defmodule MyEnumTest do
use ExUnit.Case
import ExUnit.CaptureIO
test "all?/1 works" do
assert MyEnum.all?([1, 2, 3]) == true
assert MyEnum.all?([1, nil, 3]) == false
assert MyEnum.all?([]) == true
end
test "all?/2 works" do
assert MyEnum.all?([2, 4, 6], fn x -> rem(x, 2) == 0 end) == true
assert MyEnum.all?([2, 3, 4], fn x -> rem(x, 2) == 0 end) == false
assert MyEnum.all?([], fn _ -> nil end) == true
end
test "each/2 works" do
result = capture_io(fn -> MyEnum.each(["some", "example"], fn x -> IO.puts(x) end) end)
assert result == "some\nexample\n"
assert MyEnum.each([], &IO.puts/1) == :ok
end
test "filter/2 works" do
assert MyEnum.filter([1, 2, 3], fn x -> rem(x, 2) == 0 end) == [2]
end
test "split/2 works" do
assert MyEnum.split([1, 2, 3], 2) == {[1, 2], [3]}
assert MyEnum.split([1, 2, 3], 10) == {[1, 2, 3], []}
assert MyEnum.split([1, 2, 3], 0) == {[], [1, 2, 3]}
assert MyEnum.split([1, 2, 3], -1) == {[1, 2], [3]}
assert MyEnum.split([1, 2, 3], -5) == {[], [1, 2, 3]}
end
test "take/2 works" do
assert MyEnum.take([1, 2, 3], 2) == [1, 2]
assert MyEnum.take([1, 2, 3], 10) == [1, 2, 3]
assert MyEnum.take([1, 2, 3], 0) == []
assert MyEnum.take([1, 2, 3], -1) == [3]
end
end
ExUnit.run()
Exercise: ListsAndRecursion-6
defmodule MyList do
def flatten([]), do: []
def flatten([h | t]) when is_list(h), do: flatten(h) ++ flatten(t)
def flatten([h | t]), do: [h | flatten(t)]
end
[1, 2, 3, 4, 5, 6] = MyList.flatten([1, [2, 3, [4]], 5, [[[6]]]])
Exercise: ListsAndRecursion-7
defmodule ExerciseListsAndRecursion4 do
def span(from, to) when to > from, do: [from | span(from + 1, to)]
def span(to, to), do: [to]
end
alias ExerciseListsAndRecursion4, as: Elar4
n = Kino.Input.number("n", defalut: 2)
for x <- Elar4.span(2, Kino.Input.read(n)),
x == 2 or
Elar4.span(2, x - 1) |> Enum.all?(&(rem(x, &1) != 0)),
do: x
Exercise: ListsAndRecursion-8
defmodule Order do
def calculate(orders, tax_rates) do
for order <- orders do
tax_rate = Keyword.get(tax_rates, order[:ship_to], 0)
total_amount = order[:net_amount] * (1 + tax_rate)
order ++ [total_amount: total_amount]
end
end
end
tax_rates = [NC: 0.075, TX: 0.08]
orders = [
[id: 123, ship_to: :NC, net_amount: 100.00],
[id: 124, ship_to: :OK, net_amount: 35.50],
[id: 125, ship_to: :TX, net_amount: 24.00],
[id: 126, ship_to: :TX, net_amount: 44.80],
[id: 127, ship_to: :NC, net_amount: 25.00],
[id: 128, ship_to: :MA, net_amount: 10.00],
[id: 129, ship_to: :CA, net_amount: 102.00],
[id: 130, ship_to: :NC, net_amount: 50.00]
]
Order.calculate(orders, tax_rates)