Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Chapter 10

programming-elixir-1.6/chapter-10.livemd

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?(&amp;(rem(x, &amp;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)