mirror of
https://github.com/wnagrodzki/ProgrammingElixir1.6-MyTurns.git
synced 2025-05-03 17:41:41 +02:00
Solutions for chapters 1-10
This commit is contained in:
parent
7259c70474
commit
892d716709
19 changed files with 524 additions and 0 deletions
23
Functions-1.exs
Normal file
23
Functions-1.exs
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Go into IEx. Create and run the functions that do the following:
|
||||
#
|
||||
# list_concat.([:a, :b], [:c, :d]) #=> [:a, :b, :c, :d]
|
||||
# sum.(1, 2, 3) #=> 6
|
||||
# pair_tuple_to_list.( { 1234, 5678 } ) #=> [ 1234, 5678 ]
|
||||
|
||||
list_concat = fn [a, b], [c, d] ->
|
||||
[a, b, c, d]
|
||||
end
|
||||
|
||||
IO.inspect list_concat.([1, 2], [3, 4])
|
||||
|
||||
sum = fn [a, b, c] ->
|
||||
a + b + c
|
||||
end
|
||||
|
||||
IO.puts sum.([1, 2, 3])
|
||||
|
||||
pair_tuple_to_list = fn { a, b } ->
|
||||
[a, b]
|
||||
end
|
||||
|
||||
IO.inspect pair_tuple_to_list.({1, 2})
|
15
Functions-2.exs
Normal file
15
Functions-2.exs
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Write a function that takes three arguments. If the first two are zero, return “FizzBuzz.”
|
||||
# If the first is zero, return “Fizz.” If the second is zero, return “Buzz.”
|
||||
# Otherwise return the third argument. Do not use any language features that we haven’t yet covered in this book.
|
||||
|
||||
fun = fn
|
||||
{0, 0, _} -> "FizzBuzz"
|
||||
{0, _, _} -> "Fizz"
|
||||
{_, 0, _} -> "Buzz"
|
||||
{_, _, c} -> c
|
||||
end
|
||||
|
||||
IO.puts fun.({0, 0, 1})
|
||||
IO.puts fun.({0, 1, 1})
|
||||
IO.puts fun.({1, 0, 1})
|
||||
IO.puts fun.({1, 1, 1})
|
22
Functions-3.exs
Normal file
22
Functions-3.exs
Normal file
|
@ -0,0 +1,22 @@
|
|||
# The operator rem(a, b) returns the remainder after dividing a by b.
|
||||
# Write a function that takes a single integer (n) and calls the function in the previous exercise, passing it rem(n,3), rem(n,5), and n.
|
||||
# Call it seven times with the arguments 10, 11, 12, and so on. You should get “Buzz, 11, Fizz, 13, 14, FizzBuzz, 16.
|
||||
|
||||
fun = fn
|
||||
{0, 0, _} -> "FizzBuzz"
|
||||
{0, _, _} -> "Fizz"
|
||||
{_, 0, _} -> "Buzz"
|
||||
{_, _, c} -> c
|
||||
end
|
||||
|
||||
fizzBuzz = fn n ->
|
||||
fun.({rem(n,3), rem(n, 5), n})
|
||||
end
|
||||
|
||||
IO.puts fizzBuzz.(10)
|
||||
IO.puts fizzBuzz.(11)
|
||||
IO.puts fizzBuzz.(12)
|
||||
IO.puts fizzBuzz.(13)
|
||||
IO.puts fizzBuzz.(14)
|
||||
IO.puts fizzBuzz.(15)
|
||||
IO.puts fizzBuzz.(16)
|
19
Functions-4.exs
Normal file
19
Functions-4.exs
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Write a function prefix that takes a string. It should return a new function that takes a second string.
|
||||
# When that second function is called, it will return a string containing the first string, a space, and the second string.
|
||||
#
|
||||
# iex> mrs = prefix.("Mrs")
|
||||
# #Function<erl_eval.6.82930912>
|
||||
# iex> mrs.("Smith")
|
||||
# "Mrs Smith"
|
||||
# iex> prefix.("Elixir").("Rocks")
|
||||
# "Elixir Rocks"”
|
||||
|
||||
prefix = fn p ->
|
||||
fn s ->
|
||||
"#{p} #{s}"
|
||||
end
|
||||
end
|
||||
|
||||
mrs = prefix.("Mrs")
|
||||
IO.puts mrs.("Smith")
|
||||
IO.puts prefix.("Elixir").("Rocks")
|
7
Functions-5.exs
Normal file
7
Functions-5.exs
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Use the & notation to rewrite the following:
|
||||
#
|
||||
# Enum.map [1,2,3,4], fn x -> x + 2 end
|
||||
# Enum.each [1,2,3,4], fn x -> IO.inspect x end
|
||||
|
||||
IO.inspect Enum.map [1,2,3,4], &(&1 + 2)
|
||||
Enum.each [1,2,3,4], &(IO.inspect/1)
|
22
ListsAndRecursion-1.exs
Normal file
22
ListsAndRecursion-1.exs
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Write a mapsum function that takes a list and a function. It applies the function to each element of the list and then sums the result, so
|
||||
# iex> MyList.mapsum [1, 2, 3], &(&1 * &1)
|
||||
# 14
|
||||
|
||||
defmodule MyList do
|
||||
|
||||
def mapsum(list, func) do
|
||||
mapsum(list, 0, func)
|
||||
end
|
||||
|
||||
defp mapsum([head | tail], acc, func) do
|
||||
mapsum(tail, acc + func.(head), func)
|
||||
end
|
||||
|
||||
defp mapsum([], acc, _func) do
|
||||
acc
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
IO.puts MyList.mapsum([1, 2, 3], fn (n) -> n end)
|
||||
IO.puts MyList.mapsum('A', fn (n) -> n end)
|
25
ListsAndRecursion-2.exs
Normal file
25
ListsAndRecursion-2.exs
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Write a max(list) that returns the element with the maximum value in the list. (This is slightly trickier than it sounds.)
|
||||
|
||||
defmodule MyList do
|
||||
|
||||
def maxlist([]) do
|
||||
nil
|
||||
end
|
||||
|
||||
def maxlist([hd | []]) do
|
||||
hd
|
||||
end
|
||||
|
||||
def maxlist([hd | tl]) do
|
||||
if hd > maxlist(tl) do
|
||||
hd
|
||||
else
|
||||
maxlist(tl)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
IO.puts MyList.maxlist([])
|
||||
IO.puts MyList.maxlist([1])
|
||||
IO.puts MyList.maxlist([1, 2, 5, 3])
|
25
ListsAndRecursion-3.exs
Normal file
25
ListsAndRecursion-3.exs
Normal file
|
@ -0,0 +1,25 @@
|
|||
# An Elixir single-quoted string is actually a list of individual character codes.
|
||||
# Write a caesar(list, n) function that adds n to each list element, wrapping if the addition results in a character greater than z.
|
||||
# iex> MyList.cesar('ryvkve', 13)
|
||||
|
||||
defmodule MyList do
|
||||
|
||||
def cesar([], _n) do
|
||||
[]
|
||||
end
|
||||
|
||||
def cesar([hd | []], n) do
|
||||
if hd + n < ?z do
|
||||
[hd + n]
|
||||
else
|
||||
cesar([hd], n - ?z + ?a - 1)
|
||||
end
|
||||
end
|
||||
|
||||
def cesar([hd | tl], n) do
|
||||
cesar([hd], n) ++ cesar(tl, n)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
IO.puts MyList.cesar('ryvkve', 13)
|
16
ListsAndRecursion-4.exs
Normal file
16
ListsAndRecursion-4.exs
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Write a function MyList.span(from, to) that returns a list of the numbers from from up to to.
|
||||
|
||||
defmodule MyList do
|
||||
|
||||
def span(n, n) do
|
||||
[n]
|
||||
end
|
||||
|
||||
def span(from, to) do
|
||||
[from] ++ span(from + 1, to)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
IO.inspect MyList.span(1, 1)
|
||||
IO.inspect MyList.span(1, 10)
|
86
ListsAndRecursion-5.exs
Normal file
86
ListsAndRecursion-5.exs
Normal file
|
@ -0,0 +1,86 @@
|
|||
# Implement the following Enum functions using no library functions or list comprehensions: all?, each, filter, split, and take.
|
||||
# You may need to use an if statement to implement filter. The syntax for this is
|
||||
|
||||
defmodule MyEnum do
|
||||
|
||||
def all?([], _) do
|
||||
true
|
||||
end
|
||||
|
||||
def all?( [head | tail], fun) do
|
||||
# The dot is only used when calling anonymous functions that
|
||||
# have been bound to a variable (and not functions defined inside a module).
|
||||
# The dot also reminds us that it is an anonymous function.
|
||||
fun.(head) && all?(tail, fun)
|
||||
end
|
||||
|
||||
def each([], _) do
|
||||
# noop
|
||||
end
|
||||
|
||||
def each( [head | tail], fun) do
|
||||
fun.(head)
|
||||
each(tail, fun)
|
||||
end
|
||||
|
||||
def filter([], _) do
|
||||
[]
|
||||
end
|
||||
|
||||
def filter( [head | tail], fun) do
|
||||
if fun.(head) do
|
||||
[head] ++ filter(tail, fun)
|
||||
else
|
||||
filter(tail, fun)
|
||||
end
|
||||
end
|
||||
|
||||
def split(list, count) do
|
||||
split([], list, count)
|
||||
end
|
||||
|
||||
defp split(listA, listB, 0) do
|
||||
{listA, listB}
|
||||
end
|
||||
|
||||
defp split(listA, [head | tail], count) do
|
||||
split(listA ++ [head], tail, count - 1)
|
||||
end
|
||||
|
||||
def take(_list, 0) do
|
||||
[]
|
||||
end
|
||||
|
||||
def take([], _count) do
|
||||
[]
|
||||
end
|
||||
|
||||
def take( [head | tail], count ) do
|
||||
[head] ++ take(tail, count - 1)
|
||||
end
|
||||
|
||||
def flatten([]) do
|
||||
[]
|
||||
end
|
||||
|
||||
def flatten([head | tail]) do
|
||||
if is_list(head) do
|
||||
flatten(head) ++ flatten(tail)
|
||||
else
|
||||
[head] ++ flatten(tail)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
IO.puts MyEnum.all?( [], &(&1 < 4) )
|
||||
IO.puts MyEnum.all?( [1], &(&1 < 4) )
|
||||
IO.puts MyEnum.all?( [1, 4], &(&1 < 4) )
|
||||
|
||||
MyEnum.each [1, 2, 3], &( IO.puts &1 )
|
||||
|
||||
IO.inspect MyEnum.filter [1, 2, 3, 4, 5], &( &1 < 3 )
|
||||
|
||||
IO.inspect MyEnum.split [1, 2, 3, 4, 5], 2
|
||||
|
||||
IO.inspect MyEnum.take [1, 2, 3, 4, 5], 6
|
20
ListsAndRecursion-6.exs
Normal file
20
ListsAndRecursion-6.exs
Normal file
|
@ -0,0 +1,20 @@
|
|||
# (Hard) Write a flatten(list) function that takes a list that may contain any number of sublists, which themselves may contain sublists, to any depth.
|
||||
# It returns the elements of these lists as a flat list.
|
||||
|
||||
defmodule MyEnum do
|
||||
|
||||
def flatten([]) do
|
||||
[]
|
||||
end
|
||||
|
||||
def flatten([head | tail]) do
|
||||
if is_list(head) do
|
||||
flatten(head) ++ flatten(tail)
|
||||
else
|
||||
[head] ++ flatten(tail)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
IO.inspect MyEnum.flatten([ 1, [ 2, 3, [4] ], 5, [[[6]]]])
|
34
ListsAndRecursion-7.exs
Normal file
34
ListsAndRecursion-7.exs
Normal file
|
@ -0,0 +1,34 @@
|
|||
# In the last exercise of Chapter 7, Lists and Recursion, you wrote a span function.
|
||||
# Use it and list comprehensions to return a list of the prime numbers from 2 to n.
|
||||
|
||||
defmodule MyList do
|
||||
|
||||
def prime(n) do
|
||||
numbers = Enum.to_list span(2, n)
|
||||
for x <- numbers, isPrime(x), do: x
|
||||
end
|
||||
|
||||
defp span(n, n) do
|
||||
[n]
|
||||
end
|
||||
|
||||
defp span(from, to) do
|
||||
[from] ++ span(from + 1, to)
|
||||
end
|
||||
|
||||
defp isPrime(1) do
|
||||
true
|
||||
end
|
||||
|
||||
defp isPrime(2) do
|
||||
true
|
||||
end
|
||||
|
||||
defp isPrime(n) do
|
||||
denominators = Enum.to_list span(2, n - 1)
|
||||
Enum.all? denominators, fn x -> rem(n, x) != 0 end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
IO.inspect MyList.prime(100)
|
51
ListsAndRecursion-8.exs
Normal file
51
ListsAndRecursion-8.exs
Normal file
|
@ -0,0 +1,51 @@
|
|||
# The Pragmatic Bookshelf has offices in Texas (TX) and North Carolina (NC), so we have to charge sales tax on orders shipped to these states.
|
||||
# The rates can be expressed as a keyword list (I wish it were that simple.…):
|
||||
|
||||
# tax_rates = [ NC: 0.075, TX: 0.08 ]
|
||||
# Here’s a list of orders:
|
||||
|
||||
# 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 ] ]
|
||||
# Write a function that takes both lists and returns a copy of the orders, but with an extra field, total_amount, which is the net plus sales tax.
|
||||
# If a shipment is not to NC or TX, there’s no tax applied.
|
||||
|
||||
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 ]
|
||||
]
|
||||
|
||||
defmodule Calculator do
|
||||
|
||||
def process(orders, tax_rates) do
|
||||
|
||||
for order <- orders, do: order ++ [ total_amount: total_amount(order, tax_rates) ]
|
||||
|
||||
end
|
||||
|
||||
defp total_amount(order, tax_rates) do
|
||||
tax_rate = tax_rates[order[:ship_to]]
|
||||
if tax_rate == nil do
|
||||
order[:net_amount]
|
||||
else
|
||||
order[:net_amount] + order[:net_amount] * tax_rate
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
IO.inspect Calculator.process(orders, tax_rates)
|
27
ModulesAndFunctions-1,2,3.exs
Normal file
27
ModulesAndFunctions-1,2,3.exs
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Exercise: ModulesAndFunctions-1
|
||||
# Extend the Times module with a triple function that multiplies its parameter by three.
|
||||
|
||||
# Exercise: ModulesAndFunctions-2
|
||||
# Run the result in IEx. Use both techniques to compile the file.
|
||||
|
||||
# Exercise: ModulesAndFunctions-3
|
||||
# Add a quadruple function. (Maybe it could call the double function.…)
|
||||
|
||||
defmodule Times do
|
||||
|
||||
def triple(n) do
|
||||
n*3
|
||||
end
|
||||
|
||||
def quadruple(n) do
|
||||
double(n) * double(n)
|
||||
end
|
||||
|
||||
defp double(n) do
|
||||
n*n
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
IO.puts Times.triple(1)
|
||||
IO.puts Times.quadruple(2)
|
17
ModulesAndFunctions-4.exs
Normal file
17
ModulesAndFunctions-4.exs
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Implement and run a function sum(n) that uses recursion to calculate the sum of the integers from 1 to n.
|
||||
# You’ll need to write this function inside a module in a separate file.
|
||||
# Then load up IEx, compile that file, and try your function.
|
||||
|
||||
defmodule MyModule do
|
||||
|
||||
def sum(1) do
|
||||
1
|
||||
end
|
||||
|
||||
def sum(n) do
|
||||
n + sum(n - 1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
IO.puts MyModule.sum(10)
|
16
ModulesAndFunctions-5.exs
Normal file
16
ModulesAndFunctions-5.exs
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Write a function gcd(x,y) that finds the greatest common divisor between two nonnegative integers.
|
||||
# Algebraically, gcd(x,y) is x if y is zero; it’s gcd(y, rem(x,y)) otherwise.
|
||||
|
||||
defmodule MyModule do
|
||||
|
||||
def gcd(x,0) do
|
||||
x
|
||||
end
|
||||
|
||||
def gcd(x,y) do
|
||||
gcd(y, rem(x, y))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
IO.puts MyModule.gcd(17*5, 13*5)
|
47
ModulesAndFunctions-6.exs
Normal file
47
ModulesAndFunctions-6.exs
Normal file
|
@ -0,0 +1,47 @@
|
|||
# I’m thinking of a number between 1 and 1000.…
|
||||
# The most efficient way to find the number is to guess halfway between the low and high numbers of the range.
|
||||
# If our guess is too big, then the answer lies between the bottom of the range and one less than our guess.
|
||||
# If our guess is too small, then the answer lies between one more than our guess and the end of the range.
|
||||
# Your API will be guess(actual, range), where range is an Elixir range. Your output should look similar to this:
|
||||
#
|
||||
# iex> Chop.guess(273, 1..1000)
|
||||
# Is it 500
|
||||
# Is it 250
|
||||
# Is it 375
|
||||
# Is it 312
|
||||
# Is it 281
|
||||
# Is it 265
|
||||
# Is it 273
|
||||
# 273
|
||||
# Hints:
|
||||
# - You may need to implement helper functions with an additional parameter (the currently guessed number).
|
||||
# - The div(a,b) function performs integer division.
|
||||
# - Guard clauses are your friends.
|
||||
# - Patterns can match the low and high parts of a range (a..b=4..8).
|
||||
|
||||
defmodule Chop do
|
||||
|
||||
def guess(actual, range) do
|
||||
first..last = range
|
||||
guess = div(last + first, 2)
|
||||
|
||||
guess(actual, first, last)
|
||||
end
|
||||
|
||||
defp guess(actual, first, last) when actual < div(last + first, 2) do
|
||||
IO.puts "Is it #{div(last + first, 2)}"
|
||||
guess(actual, first, div(last + first, 2))
|
||||
end
|
||||
|
||||
defp guess(actual, first, last) when actual > div(last + first, 2) do
|
||||
IO.puts "Is it #{div(last + first, 2)}"
|
||||
guess(actual, div(last + first, 2), last)
|
||||
end
|
||||
|
||||
defp guess(actual, first, last) do
|
||||
IO.puts actual
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Chop.guess(273, 1..1000)
|
26
ModulesAndFunctions-7.exs
Normal file
26
ModulesAndFunctions-7.exs
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Find the library functions to do the following, and then use each in IEx.
|
||||
# (If the word Elixir or Erlang appears at the end of the challenge, then you’ll find the answer in that set of libraries.)
|
||||
# - Convert a float to a string with two decimal digits. (Erlang)
|
||||
# - Get the value of an operating-system environment variable. (Elixir)
|
||||
# - Return the extension component of a file name (so return .exs if given "dave/test.exs"). (Elixir)
|
||||
# - Return the process’s current working directory. (Elixir)
|
||||
# - Convert a string containing JSON into Elixir data structures. (Just find; don’t install.)
|
||||
# - Execute a command in your operating system’s shell.
|
||||
|
||||
# https://erldocs.com/current/erts/erlang.html?i=4&search=float%20to#float_to_list/2
|
||||
IO.puts :erlang.float_to_list(1234.5678, [decimals: 2])
|
||||
|
||||
# https://erldocs.com/current/kernel/os.html?i=1&search=os:get#getenv/1
|
||||
IO.inspect :os.getenv('HOME')
|
||||
|
||||
# https://hexdocs.pm/elixir/Path.html#extname/1
|
||||
IO.puts Path.extname('dave/test.exs')
|
||||
|
||||
# https://hexdocs.pm/elixir/System.html#cwd/0
|
||||
IO.puts System.cwd()
|
||||
|
||||
# https://github.com/devinus/poison
|
||||
# Poison.Parser.parse!(~s({"name": "Devin Torres", "age": 27}), %{})
|
||||
|
||||
# https://hexdocs.pm/elixir/System.html#cmd/3
|
||||
IO.inspect System.cmd("echo", ["hello world"], into: IO.stream(:stdio, :line))
|
26
PatternMatching-1,2,3.exs
Normal file
26
PatternMatching-1,2,3.exs
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Exercise: PatternMatching-1
|
||||
# Which of the following will match?
|
||||
# a = [1, 2, 3] Will
|
||||
# a = 4 Will
|
||||
# 4 = a Will
|
||||
# [a, b] = [ 1, 2, 3 ] Won't
|
||||
# a = [ [ 1, 2, 3 ] ] Will
|
||||
# [a] = [ [ 1, 2, 3 ] ] Will
|
||||
# [[a]] = [ [ 1, 2, 3 ] ] Won't
|
||||
|
||||
# Exercise: PatternMatching-2
|
||||
# Which of the following will match?
|
||||
#
|
||||
# [ a, b, a ] = [ 1, 2, 3 ] Won't
|
||||
# [ a, b, a ] = [ 1, 1, 2 ] Won't
|
||||
# [ a, b, a ] = [ 1, 2, 1 ] Will
|
||||
#
|
||||
# Exercise: PatternMatching-3
|
||||
# The variable a is bound to the value 2. Which of the following will match?
|
||||
#
|
||||
# [ a, b, a ] = [ 1, 2, 3 ] Won't
|
||||
# [ a, b, a ] = [ 1, 1, 2 ] Won't
|
||||
# a = 1 Will
|
||||
# ^a = 2 Will
|
||||
# ^a = 1 Won't
|
||||
# ^a = 2 - a Won't
|
Loading…
Add table
Reference in a new issue