Three ways to convert an integer to a roman numeral

ddanbe 0 Tallied Votes 1K Views Share

Although roman numerals sneak in our lives from time to time, we(luckily) don't use them very often. Probably the reason why the Romans where not that good at calculating things. That changed, more than 1000 years later, with this person who introduced to the Western world the number system we all use today.
But let's come to the point: this is not about a conversion but about the ways to do it.
I don't even refer to the algoritm used, but C# seems to become such a rich expressive language that I'm beginning to have trouble choosing a way to do things. Are ther still other, even better ways to do this? Please let me know.
Any comment on my code is very much appriciated. :)

Thanks to nick.crane (see http://www.daniweb.com/software-development/csharp/threads/376347) who gave me the idea to try it the tuple way.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RomanDigits
{
    class RomanNumeralConverter
    {
        // Way one
        private struct RomanDigit
        {
            public string Rstr;
            public int value;
        }
        private RomanDigit[] Rom;

        // Way two
        private Dictionary<string, int> Roman;

        // Way three
        private List<Tuple<string, int>> ConvTable = new List<Tuple<string, int>>();       
           
        public RomanNumeralConverter() //construct and init  the 3 types
        {
            Rom = new RomanDigit[] 
            { 
                new RomanDigit{Rstr = "M",  value = 1000},
                new RomanDigit{Rstr = "CM", value = 900},
                new RomanDigit{Rstr = "D",  value = 500},
                new RomanDigit{Rstr = "CD", value = 400},
                new RomanDigit{Rstr = "C",  value = 100},
                new RomanDigit{Rstr = "XC", value = 90},
                new RomanDigit{Rstr = "L",  value = 50},
                new RomanDigit{Rstr = "XL", value = 40},
                new RomanDigit{Rstr = "X",  value = 10},
                new RomanDigit{Rstr = "IX", value = 9},
                new RomanDigit{Rstr = "V",  value = 5},
                new RomanDigit{Rstr = "IV", value = 4},
                new RomanDigit{Rstr = "I",  value = 1},
            };

            Roman = new Dictionary<string, int>();           
            Roman.Add("M", 1000);
            Roman.Add("CM", 900);
            Roman.Add("D", 500);
            Roman.Add("CD", 400);
            Roman.Add("C", 100);
            Roman.Add("XC", 90);
            Roman.Add("L", 50);
            Roman.Add("XL", 40);
            Roman.Add("X", 10);
            Roman.Add("IX", 9);
            Roman.Add("V", 5);
            Roman.Add("IV", 4);
            Roman.Add("I", 1);

            ConvTable = new List<Tuple<string, int>>();
            ConvTable.Add(Tuple.Create("M", 1000));
            ConvTable.Add(Tuple.Create("CM", 900));
            ConvTable.Add(Tuple.Create("D", 500));
            ConvTable.Add(Tuple.Create("CD", 400));
            ConvTable.Add(Tuple.Create("C", 100));
            ConvTable.Add(Tuple.Create("XC", 90));
            ConvTable.Add(Tuple.Create("L", 50));
            ConvTable.Add(Tuple.Create("XL", 40));
            ConvTable.Add(Tuple.Create("X", 10));
            ConvTable.Add(Tuple.Create("IX", 9));
            ConvTable.Add(Tuple.Create("V", 5));
            ConvTable.Add(Tuple.Create("IV", 4));
            ConvTable.Add(Tuple.Create("I", 1));
        }

        public string ConvertwithStruct(int Number)
        {
            string RomanStr = string.Empty;
            for (int i = 0; Number > 0; i++)
            {
                while (Rom[i].value <= Number)
                {
                    RomanStr += Rom[i].Rstr;
                    Number -= Rom[i].value;
                }
            }
            return RomanStr;
        }

        public string ConvertwithDict(int Number)
        {
            string RomanStr = string.Empty;
            for (int i = 0; Number > 0; i++)
            {
                while (Roman.ElementAt(i).Value <= Number)
                {
                    RomanStr += Roman.ElementAt(i).Key;
                    Number -= Roman.ElementAt(i).Value;
                }
            }
            return RomanStr;
        }

        public string ConvertwithTuple(int Number)
        {
            string RomanStr = string.Empty;
            for (int i = 0; Number > 0; i++)
            {
                while (ConvTable.ElementAt(i).Item2 <= Number)
                {
                    RomanStr += ConvTable.ElementAt(i).Item1;
                    Number -= ConvTable.ElementAt(i).Item2;
                }
            }
            return RomanStr;
        }
    }
}

///////Program to test this class
using System;
using System.Collections.Generic;
using System.Linq;

namespace RomanDigits
{
    class Program
    {
        static void Main(string[] args)
        {
            RomanNumeralConverter RC = new RomanNumeralConverter();

            string RomanNumeral = string.Empty;
            int DecimalNumber = 1984;
            RomanNumeral = RC.ConvertwithStruct(DecimalNumber);
            Console.WriteLine("The integer {0} is {1} in roman.", DecimalNumber, RomanNumeral);
            DecimalNumber = 1999;
            RomanNumeral = RC.ConvertwithDict(DecimalNumber);
            Console.WriteLine("The integer {0} is {1} in roman.", DecimalNumber, RomanNumeral);
            DecimalNumber = 42;
            RomanNumeral = RC.ConvertwithTuple(DecimalNumber);
            Console.WriteLine("The integer {0} is {1} in roman.", DecimalNumber, RomanNumeral);

            Console.ReadKey();
        }
    }
}
Evenbit 52 Junior Poster

At one time (not sure if they're still in the current version), Randall Hyde had highly-efficient 'Roman Numeral' output/conversion functions in the Standard Library for his HLA compiler. You might find it interesting to dig through his source.

http://hla-stdlib.svn.sourceforge.net/viewvc/hla-stdlib/
http://hla-stdlib.sourceforge.net/

ddanbe 2,724 Professional Procrastinator Featured Poster

@Evenbit: Thanks for the reply and the tip on HLA. I'm not that much interested in the conversion, but in the way to do it in C#.

Momerath 1,327 Nearly a Senior Poster Featured Poster

A recursive method using non-subtractive roman numerals:

using System;
using System.Text;

namespace ConsoleApplication1 {
    class Roman {
        String[] digits = { "", "i", "ii", "iii", "iiii", "v", "vi", "vii", "viii", "viiii" };

        public String Convert(int number) {
            String result = String.Empty;
            if (number >= 10) {
                result = MultiplyBy10(Convert(number / 10));
            }
            return result + digits[number % 10];
        }

        private String MultiplyBy10(String roman) {
            StringBuilder sb = new StringBuilder();
            foreach (char c in roman) {
                switch (c) {
                    case 'i': sb.Append('x'); break;
                    case 'v': sb.Append('l'); break;
                    case 'x': sb.Append('c'); break;
                    case 'l': sb.Append('d'); break;
                    case 'c': sb.Append('m'); break;
                    case 'd': sb.Append("mmmmm"); break;
                    case 'm': sb.Append("mmmmmmmmmm"); break;
                    default: break;
                }
            }

            return sb.ToString();
        }
    }
}
ddanbe 2,724 Professional Procrastinator Featured Poster

@Momerath: Interesting algorithm! But I guess the Romans rather liked to carve MCMXCIX into their stone walls, then mdcccclxxxxviiii, when they had the intention of writing the number 1999

Momerath 1,327 Nearly a Senior Poster Featured Poster

Actually there is no standard and you can find both types of numbers throughout roman history. Wikipedia has an interesting article on this.

ddanbe 2,724 Professional Procrastinator Featured Poster

@Momerath: Yes I mentioned the same article in my OP. But thanks for your input anyway. I'd better made a thread here so I could call this one solved. I was just curious about what datatype was the best to use. I should have reformulated my title more in the direction of what I was really after, because as everyone knows, roman numerals are too hot of a topic these days;)

Hash Collision 0 Newbie Poster

For the sake of the argument you could also implement this with classes, the implementation is similar to that of Type Struct.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RomanNumeralConvertWithClasses
{
    class MainApplication
    {
        
        static void Main(string[] args)
        {
            RomanNumeralConverter[] romArray;
            romArray = new RomanNumeralConverter[]
            {
                new RomanNumeralConverter("M",1000),
                new RomanNumeralConverter("D",500),
                new RomanNumeralConverter("C",100),
                new RomanNumeralConverter("L",50),
                new RomanNumeralConverter("X",10),
                new RomanNumeralConverter("V",5),
                new RomanNumeralConverter("I",1)
            };

            string[] romanNumerals = new string[] { "M", "M", "M", "D", "C", "C", "C", "L", "X", "X", "X", "V", "I", "I", "I" }; // 3888
            int total = 0;
            for (int i = 0; i < romanNumerals.Length; i++)
            {
                for (int j = 0; j < romArray.Length; j++)
                {
                    if (romanNumerals[i] == romArray[j].key)
                    {
                        total += romArray[j].value;
                    }
                }
            }
            Console.WriteLine(total);

        }
    }
    class RomanNumeralConverter
    {
        public string key { get; set; }
        public int value { get; set; }

        public RomanNumeralConverter()
        {

        }
        public RomanNumeralConverter(string key, int value)
        {
            this.key = key;
            this.value = value;
        }
    }
}
Evenbit 52 Junior Poster

because as everyone knows, roman numerals are too hot of a topic these days

Actually, Roman Numerals are quite common in industrial settings. For instance, "25L" would mean 25 stacks of 50 items. You probably run into them quite often on a daily basis without realising it because you are simply not looking for them or simply unaware that that is what the letter means in that particular context.

skatamatic 371 Practically a Posting Shark

Actually, Roman Numerals are quite common in industrial settings. For instance, "25L" would mean 25 stacks of 50 items. You probably run into them quite often on a daily basis without realising it because you are simply not looking for them or simply unaware that that is what the letter means in that particular context.

Umm...What industrial settings are you talking about? I work in industrial settings on a regular basis and for the most part things are kept as clear as possible to avoid...umm...people dieing.

gracefull 0 Newbie Poster

Three ways to convert an integer to a roman numeral in java

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.