Hey!
Welcome back to another episode of exercism.io exercise wherein we practice our logic and problem solving capabilities.
Okay! so I got this new challenge called Converting a number into a Roman Numeral
.
It says there that it is easy, but as for me it wasn't hahaha!
Start to Analyze!
As for me, the key hints to solve the problem is by the power of algorithm
and pattern matching
! Hooray ๐ฅ
Honestly I struggled a lot on juggling different ideas on how to solve this problem. So first I started to gather some information that can be useful for me.
Solution
@doc """
Convert the number to a roman numeral.
"""
@spec numeral(pos_integer) :: String.t()
def numeral(number) do
end
Given the function doc and spec, I started to think that I need to;
convert integer to string
split and turn them into an array
@doc """
Convert the number to a roman numeral.
"""
@spec numeral(pos_integer) :: String.t()
def numeral(number) do
numbers =
number
|> Integer.to_string()
|> String.split("", trim: true)
end
In this way, I thought I could manipulate them one by one and match the corresponding values according to their place number. So to satisfy it;
- using
Enum.with_index()
I jump into the data and transform them into arrays elements together with their indexes.
@doc """
Convert the number to a roman numeral.
"""
@spec numeral(pos_integer) :: String.t()
def numeral(number) do
numbers =
number
|> Integer.to_string()
|> String.split("", trim: true)
|> Enum.with_index()
end
Now the next thing that I did was to transform the data into a map
because I thought in this was I could pattern match depending on their
index as their place number
@doc """
Convert the number to a roman numeral.
"""
@spec numeral(pos_integer) :: String.t()
def numeral(number) do
numbers =
number
|> Integer.to_string()
|> String.split("", trim: true)
|> Enum.with_index()
|> Enum.map(fn {x, index} ->
{index, String.to_integer(x)}
end)
|> Map.new()
end
Finally, I created a private function named to_numeral/1
that accepts a map.
@doc """
Convert the number to a roman numeral.
"""
@spec numeral(pos_integer) :: String.t()
def numeral(number) do
numbers =
number
|> Integer.to_string()
|> String.split("", trim: true)
|> Enum.with_index()
|> Enum.map(fn {x, index} ->
{index, String.to_integer(x)}
end)
|> Map.new()
|> to_numeral
end
WTF is to_numeral/1
been doing? ๐ค
So the next plan that I have is to create a new private function that will turn this Map
into Roman Numeral
values.
defp to_numeral(%{0 => thousands, 1 => hundreds, 2 => tens, 3 => ones}) do
parse(thousands, :thousands) <> to_numeral(%{0 => hundreds, 1 => tens, 2 => ones})
end
defp to_numeral(%{0 => hundreds, 1 => tens, 2 => ones}) do
parse(hundreds, :hundreds) <> to_numeral(%{0 => tens, 1 => ones})
end
defp to_numeral(%{0 => tens, 1 => ones}) do
parse(tens, :tens) <> to_numeral(%{0 => ones})
end
defp to_numeral(%{0 => ones}) do
parse(ones, :one)
end
Yeah I know! there are so many movings parts here. It kind a hard to admit that I did all of this but life isn't always perfect. I need to be dumb sometimes for me to learn. So you know how this ends.
I created a private function parse/2
that turns this numbers according to their equivalent value in
roman characters.
So in all, I've created about 90+
line of code just to deliver my answer. For the next blog, my goal is to refactor this one and come up with
a much better approach and apply it to my future problem solving at exercism: track elixir.
You can check out my solution here