#### Learn how to build iOS apps

##### Get started with iOS 13 and Swift 5

Sign up for my iOS development course, and learn how to build great iOS 13 apps with Swift 5 and Xcode 11.

Roman numerals, such as **MMXIX**, are exciting! In this article, we’re going to write some code that converts any integer number to a roman numeral. It’s a fun, short exercise that touches on many aspects of the Swift programming language. It’s perfect if you have a spare minute or two to play with code!

Ready? Let’s go.

- What Are Roman Numerals?
- Setting Up The “roman(number:)” Function
- Converting Numbers To Roman Numerals
- Taking Numerals Like “IX” Into Account
- Further Reading

A big thanks to Les from the United Kingdom, for the inspiration to write this article! Keep having fun coding :-)

Before we start, let’s do a quick refresher on *roman numerals*. Roman numerals are a numeric system that originated in ancient Rome. With it, a number like *2019* is written as **MMXIX**, in letters of the Latin alphabet.

Roman numerals use 7 symbols, each with a fixed integer number:

Symbol |
I | V | X | L | C | D | M |
---|---|---|---|---|---|---|---|

Value |
1 | 5 | 10 | 50 | 100 | 500 | 1000 |

Roman numerals were used until the late Middle Ages (1500 CE), but in our modern world they still have their uses! You see roman numerals on clocks, paper currency, buildings, monuments, and even movie credits.

The roman numerals system is basically a decimal or “base 10” number system, written from left to right. Instead of each *power of ten* having its own decimal place, roman numerals “add up” symbols to a given number. It’s easiest to think of them as “tally marks.”

For example, the number 2019 is written as:

**MM**for 2 times a thousand**X**for once a ten**IX**for “one before 10”, i.e.*9*

That last symbol, **IX**, is special. Instead of writing **VIIII**, for *“5 + 4 = 9”*, you write **IX**, for *“10 – 1 = 9”*. This is called “subtractive notation”. It’s quite useful, because it’ll save you from writing lots of symbols! **IX** is simply shorter than **VIIII**.

The same trick applies to other symbols too. For example, 40 is **XL** instead of **XXXX**, 90 is **XC** instead of **LXXXX**, 400 is **CD**, and 900 is **CM**. It doesn’t work for non-adjacent symbols, i.e. 999 is not **IM** but **CMXCIX**.

Sign up for my iOS development course, and learn how to build great iOS 13 apps with Swift 5 and Xcode 11.

We’re going to write a Swift function that can convert arbitrary integer numbers to roman numerals. Let’s get started!

First, let’s think about the input and output for this function. The function needs an `Int`

value as input, and outputs a value of type `String`

. So, our function declaration will be this:

```
func roman(number: Int) -> String
{
}
```

The `roman(number:)`

function takes a value of type `Int`

for the `number`

parameter and outputs a value of type `String`

. Perfect!

Next, inside the function, we’re going to define the roman numeral system, like this:

```
let decimals = [1000, 500, 100, 50, 10, 5, 1]
let numerals = ["M", "D", "C", "L", "X", "V", "I"]
```

The above code defines exactly the same as the table in the previous section. Every decimal value has a roman numeral, such as `C = 100`

. Both arrays have exactly the same amount of items, so we can use identical index numbers to look up numerals by decimals.

Two things stand out here:

- We’ve sorted the arrays from largest-to-smallest. This is crucial for our implementation, as you’ll see later on.
- We haven’t yet added the
**IX**,**CM**, etc. “subtractive notation” symbols, which we’ll do later.

Next, we’re coding this inside the function:

```
var result = ""
var number = number
```

The above code first defines a variable `result`

of type `String`

. We’re going to use this variable to build up the resulting roman numeral, i.e. the output string.

The local variable `number`

is declared with the function parameter `number`

(which is a bit ugly). Parameters are constants, so they can’t be changed. By “redeclaring” `number`

as a variable, we’re now allowed to change `number`

. We couldn’t have used the `inout`

keyword here, because that would have produced the unintended side-effect of *changing* the function’s argument, as you’ll see later on.

Why don’t we use a dictionary for `decimals`

and `numerals`

? Well, dictionary items don’t have a sort order! The algorithm we’re about to write relies on a larger-to-smaller sort order, which won’t work with dictionaries. An alternative would be using *tuples*, or sorting the dictionary and decomposing its keys and values – but what we have now is much simpler.

Alright, we’re getting to the core of the algorithm. Before we start, it’s worthwhile to consider how we would convert a number to roman numerals with *pen and paper*. This is always a great idea if you need to design an algorithm.

Here’s how we would convert 1776:

- See that we need one
**M**, for a thousand – which leaves 776 - See that we need
**DCC**, for*“500 + 100 + 100 = 700”*, which leaves 76 - See that we need
**LXX**, for*“50 + 10 + 10 = 70”*, which leaves 6 - Finally, we need
**VI**for*“5 + 1 = 6”*, resulting in**MDCCLXXVI**

We could say that we’re subtracting numbers from 1776 until we reach zero. Each number we subtract results in a different symbol added to the final result. Would it be possible to put that workflow into an algorithm?

First, let’s start with a `while`

loop. Like this:

```
while number > 0
{
}
```

This loop will keep iterating for as long as `number`

is greater than `0`

. Differently said, it’ll stop if `number`

is zero. We don’t know how many iterations we need, so we’re using `while`

instead of a for loop.

Next, we want to loop over every item in the `decimals`

array. We’re going to attempt to subtract this decimal number from `number`

. That’s why we sorted the `decimals`

array from largest-to-smallest, so we can see if a decimal would “fit into” the input number.

So, we write this inside the `while`

loop:

```
for (index, decimal) in decimals.enumerated()
{
if number - decimal >= 0 {
}
}
```

The for loop is used to iterate over the `decimals`

array. We’re using the `enumerated()`

function so we can access both the array index and the array value, with the `index`

and `decimal`

constants in the *tuple*.

Inside the for loop, we’re checking if `number`

minus `decimal`

is greater or equal to zero, with an if block. This is exactly what we did in our pen-and-paper workflow, earlier.

- Take for example the
`1000 = M`

for`number = 1776`

. Is 1776 minus 1000 greater than zero?*Yes it is!*We now know that 1776 can accommodate one**M**for its thousand. - Another example:
`500 = D`

for`number = 99`

. Is 99 minus 500 greater than zero?*No it’s not!*We now know that the number 99 doesn’t include a**D**.

Let’s finish the code by writing the following inside the `if`

block:

```
number -= decimal
result += numerals[index]
break
```

Here’s what happens on those 3 lines:

`decimal`

is subtracted from`number`

. When we’ve found that a decimal “fits in” the input number, we’ve found a roman numeral, so that decimal can be subtracted from the input number.`numerals[index]`

is appended to`result`

, so the found roman numeral in the iteration is written down by using`index`

. Remember that`index`

corresponds to the index number of both the decimal and the roman numeral!`break`

exits this iteration of the`for`

loop, because we’ve found a roman literal, and thus the`while`

loop continues with its next iteration

Finally, we return the resulting value in the function with:

```
return result
```

Here’s the complete code once more:

```
func roman(number: Int) -> String
{
let decimals = [1000, 500, 100, 50, 10, 5, 1]
let numerals = ["M", "D", "C", "L", "X", "V", "I"]
var result = ""
var number = number
while number > 0
{
for (index, decimal) in decimals.enumerated()
{
if number - decimal >= 0 {
number -= decimal
result += numerals[index]
break
}
}
}
return result
}
```

Let’s go over the core principles of the algorithm.

- The
`while`

loop ensures that we’re iterating for as long as`number`

is greater than`0`

. If`number`

equals`0`

, the algorithm stops. The code that subtracts something from`number`

, is inside the`for`

loop:`number -= decimal`

. When we’ve found a roman numeral, we’re subtracting its value, to move towards zero. - The
`for`

loop, and its inner`if`

block, is what checks every decimal against the current`number`

value. It’s as if it’s trying to “fit” a roman numeral inside the number. Because, if it fits, we’ve got a match! - When the algorithm finds a roman numeral, for example
**M**for a 1000 in 1776, it’ll subtract that decimal from`number`

and append the numeral to`result`

. The loop also needs to be broken with`break`

, because the loop needs to start over from the beginning.

You can see the algorithm do its work more clearly, by adding the following line inside the `if`

block:

```
print("Found \(numerals[index]) for \(decimal)")
```

You can run the function with the following code:

```
print(roman(number: 2019))
print(roman(number: 1776))
print(roman(number: 1999))
```

For the year 2019, the output is:

```
Found M for 1000
Found M for 1000
Found X for 10
Found V for 5
Found I for 1
Found I for 1
Found I for 1
Found I for 1
```

But… what’s going on there!? Wasn’t 2019 supposed to be **MMXIX**?

We haven’t yet incorporated *subtractive notation* in our algorithm. We discussed before that some symbols, such as for 9, are written as **IX** or *“one before 10”*, instead of **VIIII**.

The algorithm we’ve coded so far works by attempting to subtract decimals from the input value, substituting them for roman numerals. We could adjust the algorithm to incorporate numerals like **IX** with some complicated code, but as it turns out, supporting subtractive notation is incredibly simple.

Replace the declaration at the top of the function with:

```
let decimals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
let numerals = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
```

Instead of only using the basic values **M**, **D**, **C**, **L**, **X**, **V**, and **I**, we’ve simply added the other symbols, like **CM**, to the array as well. For our algorithm, it doesn’t matter much if you subtract *900*, or *500* and 4 times *100*! As long as the decimals and numerals are in descending order, the subtraction mechanism works perfectly fine.

And that’s everything there’s to it! Here, try out the code for yourself with this Swift sandbox:

func roman(number: Int) -> String

{

let decimals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]

let numerals = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]

var result = ""

var number = number

while number > 0

{

for (index, decimal) in decimals.enumerated()

{

if number - decimal >= 0 {

number -= decimal

result += numerals[index]

break

}

}

}

return result

}

print(roman(number: 2019))

print(roman(number: 1776))

print(roman(number: 1999))

{

let decimals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]

let numerals = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]

var result = ""

var number = number

while number > 0

{

for (index, decimal) in decimals.enumerated()

{

if number - decimal >= 0 {

number -= decimal

result += numerals[index]

break

}

}

}

return result

}

print(roman(number: 2019))

print(roman(number: 1776))

print(roman(number: 1999))

Awesome! We’ve converted any arbitrary decimal value to roman numerals. It’s a fun, short programming exercise that touches on many interesting parts of Swift syntax.

But… what about converting numerals back to integer values? We’ll leave that for another day! If you’re up for a challenge, however, try to find the longest roman numeral between 1 and 3000.

Want to learn more? Check out these Swift exercises:

- Playing With Code: Insertion Sort In Swift
- Let’s Solve The FizzBuzz Challenge In Swift
- How To: Shuffling An Array In Swift Explained

Sign up for my iOS development course, and learn how to build great iOS 13 apps with Swift 5 and Xcode 11.

**Hi, I'm Reinder.**

I help developers play with code.

- How To Learn iOS App Development
- 27 App Marketing Strategies That Just Work
- How To Make An App (In 9 Steps)
- For Loops In Swift (How To)
- How To: Pass Data Between View Controllers In Swift (Extended)
- How To Solve SIGABRT Error In Xcode
- Working With Codable And JSON In Swift
- » Show latest