Bob is a lackadaisical teenager. In conversation, his responses are very limited.
Bob answers ‘Sure.’ if you ask him a question.
He answers ‘Whoa, chill out!’ if you yell at him.
He answers ‘Calm down, I know what I’m doing!’ if you yell a question at him.
He says ‘Fine. Be that way!’ if you address him without actually saying anything.
He answers ‘Whatever.’ to anything else.
Bob’s conversational partner is a purist when it comes to written communication and always follows normal rules regarding sentence punctuation in English.
解答
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
defmoduleBobdo defhey(input) do conddo String.trim(input) == "" -> "Fine. Be that way!" shouting?(input) && question?(input) -> "Calm down, I know what I'm doing!" shouting?(input) -> "Whoa, chill out!" question?(input) -> "Sure." true -> "Whatever." end end
Recite the lyrics to that beloved classic, that field-trip favorite: 99 Bottles of Beer on the Wall.
Note that not all verses are identical.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
99 bottles of beer on the wall, 99 bottles of beer. Take one down and pass it around, 98 bottles of beer on the wall.
98 bottles of beer on the wall, 98 bottles of beer. Take one down and pass it around, 97 bottles of beer on the wall.
97 bottles of beer on the wall, 97 bottles of beer. Take one down and pass it around, 96 bottles of beer on the wall. ... 2 bottles of beer on the wall, 2 bottles of beer. Take one down and pass it around, 1 bottle of beer on the wall.
1 bottle of beer on the wall, 1 bottle of beer. Take it down and pass it around, no more bottles of beer on the wall.
No more bottles of beer on the wall, no more bottles of beer. Go to the store and buy some more, 99 bottles of beer on the wall.
For bonus points
Did you get the tests passing and the code clean? If you want to, these are some additional things you could try:
Remove as much duplication as you possibly can.
Optimize for readability, even if it means introducing duplication.
If you’ve removed all the duplication, do you have a lot of conditionals? Try replacing the conditionals with polymorphism, if it applies in this language. How readable is it?
Then please share your thoughts in a comment on the submission. Did this experiment make the code better? Worse? Did you learn anything from it?
defmoduleBeerSongdo @doc""" Get a single verse of the beer song """ @spec verse(integer) :: String.t() defverse(0) do """ No more bottles of beer on the wall, no more bottles of beer. Go to the store and buy some more, 99 bottles of beer on the wall. """ end
defverse(1) do """ 1 bottle of beer on the wall, 1 bottle of beer. Take it down and pass it around, no more bottles of beer on the wall. """ end
defverse(number) do """ #{number} bottles of beer on the wall, #{number} bottles of beer. Take one down and pass it around, #{number - 1} bottles of beer on the wall. """ end
@doc""" Get the entire beer song for a given range of numbers of bottles. """ @spec lyrics(Range.t()) :: String.t() deflyrics(default \\99..0) do default |> Enum.map(&verse/1) |> Enum.join("\n") end end
重點提示
Enum.map 的定義如下
map(enumerable, fun)
Returns a list where each element is the result of invoking fun on each corresponding element of enumerable.
For maps, the function expects a key-value tuple.
Range 是個 enumerable,所以我們可以使用 map 這個函式,針對裡面所有的元素都來執行 fun,這邊也是一個典型的利用自我遞迴來取代迴圈的例子喔
Given a phrase, count the occurrences of each word in that phrase.
For example for the input “olly olly in come free“
1 2 3 4
olly: 2 in: 1 come: 1 free: 1
Words are compared case-insensitively. The keys are lowercase.
解答
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
defmoduleWordCountdo @doc""" Count the number of words in the sentence. Words are compared case-insensitively. """ @spec count(String.t()) :: map defcount(sentence) do String.downcase(sentence) |> String.split([" ", "_", ":", "&", "@", "%", "^", "$", ",", "!"], trim:true) |> Enum.reduce(%{}, &word_add/2) end
defpword_add(word, acc) do Map.update(acc, word, 1, &(&1 + 1)) end end
Invokes fun for each element in the enumerable with the accumulator.
The initial value of the accumulator is acc. The function is invoked for each element in the enumerable with the accumulator. The result returned by the function is used as the accumulator for the next iteration. The function returns the last accumulator.
If key is present in map with value value, fun is invoked with argument value and its result is used as the new value of key. If key is not present in map, initial is inserted as the value of key. The initial value will not be passed through the update function.
Map.update(acc, word, 1, &(&1 + 1)) 此處的解釋為從 acc(Enum.reduce 中的 accumulator) 這個 map 中找尋是否有 word 有的話就更新(利用函式 &(&1 + 1)),沒有的話就新增 word 到 acc 中,最後回傳 map(accumulator)
Ex4: Roman Numerals
題目
Write a function to convert from normal numbers to Roman Numerals.
The Romans were a clever bunch. They conquered most of Europe and ruled it for hundreds of years. They invented concrete and straight roads and even bikinis. One thing they never discovered though was the number zero. This made writing and dating extensive histories of their exploits slightly more challenging, but the system of numbers they came up with is still in use today. For example the BBC uses Roman numerals to date their programmes.
The Romans wrote numbers using letters - I, V, X, L, C, D, M. (notice these letters have lots of straight lines and are hence easy to hack into stone tablets).
1 2 3
1 => I 10 => X 7 => VII
There is no need to be able to convert numbers larger than about 3000. (The Romans themselves didn’t tend to go any higher)
Wikipedia says: Modern Roman numerals … are written by expressing each digit separately starting with the left most digit and skipping any digit with a value of zero.
To see this in practice, consider the example of 1990.
@doc""" Convert the number to a roman number. """ @spec numeral(pos_integer) :: String.t() defnumeral(0), do:"" defnumeral(number) do # 檢查數字有沒有大於 list, 有的話則輸出該羅馬字並且數字相減, 重複此步驟 {match_value_x, match_value_y} = Enum.find(@mapping, fn {x, _} -> number >= x end) # 使用 <> 來連接輸出之羅馬字 match_value_y <> numeral(number - match_value_x) end end
在我們利用 mix new 新增專案後,會一併產生檔案 .formatter.exs,這個檔案其實是給 mix format 使用的,mix format 是一個 task,它可以自動格式化你的程式碼,讓你的程式碼符合規則更漂亮一點,我們可以測試一下,修改原本的檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
defmoduleMyAppdo defhellodo :world end defhello(:one) do "hello world" end defhello(:two) do "hello world hello world" end defhello(:three) do "hello world hello world hello world" end defhello(_) do "null" end end
defmoduleGeometrydo defarea({:rectangle, a, b}) do a * b end defarea({:square, a}) do a * a end defarea({:circle, r}) do r * r * 3.14 end defarea(unknown) do {:error, {:unknown_shape, unknown}} end end
Atom 是一個被命名的常數,它很類似 C++ 的 enumeration,在使用上以冒號開頭,後面搭配一個名稱,而這個名稱就代表它本身(的值),在 runtime 的時候,這個名稱就會被存在 atom table 內,當你把一個 atom 指派給某個變數的時候,這個 atom 不會直接被指派而是使用參考的方式從 atom table 中使用 atom
我對於 atom 的理解就是,把它當作一個 key-value 的 key 使用,這個 key 本身沒有意義,就只是一個名稱,只有在 key 有對應關係時才有意義,舉個例子,我想要創造一個變數叫做 name 並且把這個變數當作是 key-value 中的 key,我只要建立一個 atom 名為 :name 就可以使用它了,如下範例,這個 atom 在 map 中的關係就對應到 "Bob" 這個字串這樣子
iex(3)> ~s/the cat in the hat on the mat/ "the cat in the hat on the mat" iex(4)> ~s(This is also a string) "This is also a string" iex(5)> ~s|This is also a string| "This is also a string"