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

Chapter 11

programming-elixir-1.6/chapter-11.livemd

Chapter 11

Mix.install([
  {:kino, "~> 0.8"}
])

Exercise: StringsAndBinaries-1, 2, 4

defmodule CharList do
  def printable([]), do: true
  def printable([head | tail]) when head in ?\s..?~, do: printable(tail)
  def printable(_), do: false

  def anagram?(word1, word2), do: normalize(word1) == normalize(word2)
  defp normalize(word), do: word |> :string.lowercase() |> :lists.sort() |> :string.trim()

  def calculate(expression) do
    [term1, operator, term2] = :re.split(expression, ' ')
    calculate(String.to_integer(term1), String.to_integer(term2), operator)
  end

  defp calculate(term1, term2, "+"), do: term1 + term2
  defp calculate(term1, term2, "-"), do: term1 - term2
  defp calculate(term1, term2, "*"), do: term1 * term2
  defp calculate(term1, term2, "/"), do: term1 / term2
end

true = CharList.printable('Hello, world!')
false = CharList.printable('Hello, world!' ++ [0])

true = CharList.anagram?('New York Times', 'monkeys write')
false = CharList.anagram?('hello', 'world')

CharList.calculate('123 + 27')

Exercise: StringsAndBinaries-3

'cat' itself is not a codepoint. Therefore, ['cat', 100, 111, 103], which is [[99, 97, 116], 100, 111, 103], is not shown as a string.

Exercise: StringsAndBinaries-5 & 6

defmodule MyString do
  def center(strings) do
    width = strings |> Enum.map(&String.length/1) |> Enum.max()
    strings |> Enum.map(&indent_to_centre(&1, width)) |> Enum.each(&IO.puts/1)
  end

  defp indent_to_centre(str, width) do
    intents = div(width - String.length(str), 2)
    String.duplicate(" ", intents) <> str
  end

  def capitalize_sentences(str) do
    str
    |> String.split(". ")
    |> Enum.map_join(". ", &amp;String.capitalize/1)
  end
end

MyString.center(["cat", "zebra", "elephant"])

"Oh. A dog. Woof. " = MyString.capitalize_sentences("oh. a DOG. woof. ")

Exercise: StringsAndBinaries-7

defmodule Order do
  @tax_rates [NC: 0.075, TX: 0.08]

  def calculate(file_path) do
    file_path
    |> File.stream!()
    |> Stream.drop(1)
    |> Stream.map(&amp;String.trim/1)
    |> Stream.map(&amp;parse/1)
    |> sales_tax()

    # Enum version
    # file_path
    # |> File.read!()
    # |> String.split("\n", trim: true)
    # |> Enum.drop(1)
    # |> Enum.map(&parse/1)
    # |> sales_tax()
  end

  defp parse(row) do
    [id, ship_to, net_amount] = String.split(row, ",")

    [
      id: String.to_integer(id),
      ship_to: ship_to |> String.trim_leading(":") |> String.to_atom(),
      net_amount: String.to_float(net_amount)
    ]
  end

  def sales_tax(orders, tax_rates \\ @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
file_input = Kino.Input.file("Sales information")
value = Kino.Input.read(file_input)
Order.calculate(value.path)