Roman numerals to integers

前端 未结 14 887
不思量自难忘°
不思量自难忘° 2020-12-05 20:56

I have a transfer with products that unfortunately has to get matched by product name. The biggest issue here is I might get duplicate products on account of roman numbers.

14条回答
  •  自闭症患者
    2020-12-05 21:19

    This is my solution:

        /// 
        /// Converts a Roman number string into a Arabic number
        /// 
        /// the Roman number string
        /// the Arabic number (0 if the given string is not convertible to a Roman number)
        public static int ToArabicNumber(string romanNumber)
        {
            string[] replaceRom = { "CM", "CD", "XC", "XL", "IX", "IV" };
            string[] replaceNum = { "DCCCC", "CCCC", "LXXXX", "XXXX", "VIIII", "IIII" };
            string[] roman = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
            int[] arabic = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
            return Enumerable.Range(0, replaceRom.Length)
                .Aggregate
                (
                    romanNumber,
                    (agg, cur) => agg.Replace(replaceRom[cur], replaceNum[cur]),
                    agg => agg.ToArray()
                )
                .Aggregate
                (
                    0,
                    (agg, cur) =>
                    {
                        int idx = Array.IndexOf(roman, cur.ToString());
                        return idx < 0 ? 0 : agg + arabic[idx];
                    },
                    agg => agg
                );
        }
    
        /// 
        /// Converts a Arabic number into a Roman number string
        /// 
        /// the Arabic number
        /// the Roman number string
        public static string ToRomanNumber(int arabicNumber)
        {
            string[] roman = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
            int[] arabic = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
            return Enumerable.Range(0, arabic.Length)
                .Aggregate
                (
                    Tuple.Create(arabicNumber, string.Empty),
                    (agg, cur) =>
                    {
                        int remainder = agg.Item1 % arabic[cur];
                        string concat = agg.Item2 + string.Concat(Enumerable.Range(0, agg.Item1 / arabic[cur]).Select(num => roman[cur]));
                        return Tuple.Create(remainder, concat);
                    },
                    agg => agg.Item2
                );
        }
    

    Here's the Explanation how the methods work:

    ToArabicNumber

    First aggregation step is to Replace the Roman Number special cases (e.g.: IV -> IIII). Second Aggregate step simply sums up the equivalent Arabic number of the Roman letter (e.g. V -> 5)

    ToRomanNumber:

    I start the aggregation with the given Arabic number. For each step the number will be divided by the equivalent number of the Roman letter. The remainder of this division is then the input for the next step. The division Result will be translated to the Equivalent Roman Number character which will be appended to the result string.

提交回复
热议问题