Exercism: Roman Numeral

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

ย