programing

정수를 로마 숫자로 변환

nasanasas 2021. 1. 9. 10:09
반응형

정수를 로마 숫자로 변환


숫자를 로마 숫자로 변환하는 함수를 작성하려고합니다. 이것은 지금까지 내 코드입니다. 그러나 400 미만의 숫자로만 작동합니다.이 변환을 수행하는 빠르고 쉬운 방법이 있습니까? 아니면 모든 경우를 처리하도록 기존 코드를 확장 할 수 있습니까? 도움을 주셔서 미리 감사드립니다.

static string convertroman(int number)
    {
        int l = number / 10;
        StringBuilder sb = new StringBuilder();
        for (int m = 0; m <= l; m++)
        {
            if (l == 0)
            {
                break;
            }
            if (l == 5)
            {
                sb = sb.Append(ro.L.ToString());
                break;
            }
            if (l == 4)
            {
                sb = sb.Append(ro.X.ToString()).Append(ro.L.ToString());
                break;
            }
            if (l == 9)
            {
                sb = sb.Append(ro.X.ToString()).Append(ro.C.ToString());
                break;
            }
            if (l == 10)
            {
                sb = sb.Append(ro.C.ToString());
                break;
            }

            if (l > 5 && l < 9)
            {
                sb = sb.Append(ro.L.ToString());
                l = l - 5;
                m = 0;
                // break;
                continue;
            }
            if (l > 10)
            {
                sb = sb.Append(ro.C.ToString());
                l = l - 10;
                m = 0;
                // continue;

            }
            else
            {
                sb = sb.Append(ro.X.ToString());
            }

        }
        int z = number % 10;
        for (int x = 0; x <= z; x++)
        {
            if (z == 0)
            {
                break;
            }
            if (z == 5)
            {
                sb = sb.Append(ro.V.ToString());
                break;
            }
            if (z == 4)
            {
                sb = sb.Append(ro.I.ToString()).Append(ro.V.ToString());
                break;
            }
            if (z == 9)
            {
                sb = sb.Append(ro.I.ToString()).Append(ro.X.ToString());
                break;
            }
            if (z == 10)
            {
                sb = sb.Append(ro.X.ToString());
                break;
            }
            if (z > 5 && z < 9)
            {
                sb = sb.Append(ro.V.ToString());
                z = z - 5;
                x = 0;
            }
            else
            {
                sb.Append(ro.I.ToString());
            }              

        }
        return sb.ToString();           
    }

간단하고 간결한 방법을 사용해보십시오.

public static string ToRoman(int number)
{
    if ((number < 0) || (number > 3999)) throw new ArgumentOutOfRangeException("insert value betwheen 1 and 3999");
    if (number < 1) return string.Empty;            
    if (number >= 1000) return "M" + ToRoman(number - 1000);
    if (number >= 900) return "CM" + ToRoman(number - 900); 
    if (number >= 500) return "D" + ToRoman(number - 500);
    if (number >= 400) return "CD" + ToRoman(number - 400);
    if (number >= 100) return "C" + ToRoman(number - 100);            
    if (number >= 90) return "XC" + ToRoman(number - 90);
    if (number >= 50) return "L" + ToRoman(number - 50);
    if (number >= 40) return "XL" + ToRoman(number - 40);
    if (number >= 10) return "X" + ToRoman(number - 10);
    if (number >= 9) return "IX" + ToRoman(number - 9);
    if (number >= 5) return "V" + ToRoman(number - 5);
    if (number >= 4) return "IV" + ToRoman(number - 4);
    if (number >= 1) return "I" + ToRoman(number - 1);
    throw new ArgumentOutOfRangeException("something bad happened");
}

여기 훨씬 더 간단한 알고리즘이 있습니다. 용서하세요. C #을 모르기 때문에 JavaScript로 작성하고 있지만 동일한 알고리즘이 적용되어야합니다 (알고리즘을 이해할 수 있도록 주석을 달았습니다).

function intToRoman(int) {

    // create 2-dimensional array, each inner array containing 
    // roman numeral representations of 1-9 in each respective 
    // place (ones, tens, hundreds, etc...currently this handles
    // integers from 1-3999, but could be easily extended)
    var romanNumerals = [
        ['', 'i', 'ii', 'iii', 'iv', 'v', 'vi', 'vii', 'viii', 'ix'], // ones
        ['', 'x', 'xx', 'xxx', 'xl', 'l', 'lx', 'lxx', 'lxxx', 'xc'], // tens
        ['', 'c', 'cc', 'ccc', 'cd', 'd', 'dc', 'dcc', 'dccc', 'cm'], // hundreds
        ['', 'm', 'mm', 'mmm'] // thousands
    ];

    // split integer string into array and reverse array
    var intArr = int.toString().split('').reverse(),
        len = intArr.length,
        romanNumeral = '',
        i = len;

    // starting with the highest place (for 3046, it would be the thousands 
    // place, or 3), get the roman numeral representation for that place 
    // and append it to the final roman numeral string
    while (i--) {
        romanNumeral += romanNumerals[ i ][ intArr[i] ];
    }

    return romanNumeral;

}

console.log( intToRoman(3046) ); // outputs mmmxlvi

이 클래스를 만들었습니다. decimal <=> roman

public static class Roman
{
    public static readonly Dictionary<char, int> RomanNumberDictionary;
    public static readonly Dictionary<int, string> NumberRomanDictionary;

    static Roman()
    {
        RomanNumberDictionary = new Dictionary<char, int>
        {
            { 'I', 1 },
            { 'V', 5 },
            { 'X', 10 },
            { 'L', 50 },
            { 'C', 100 },
            { 'D', 500 },
            { 'M', 1000 },
        };

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

    public static string To(int number)
    {
        var roman = new StringBuilder();

        foreach (var item in NumberRomanDictionary)
        {
            while (number >= item.Key)
            {
                roman.Append(item.Value);
                number -= item.Key;
            }
        }

        return roman.ToString();
    }

    public static int From(string roman)
    {
        int total = 0;

        int current, previous = 0;
        char currentRoman, previousRoman = '\0';

        for (int i = 0; i < roman.Length; i++)
        {
            currentRoman = roman[i];

            previous = previousRoman != '\0' ? RomanNumberDictionary[previousRoman] : '\0';
            current = RomanNumberDictionary[currentRoman];

            if (previous != 0 && current > previous)
            {
                total = total - (2 * previous) + current;
            }
            else
            {
                total += current;
            }

            previousRoman = currentRoman;
        }

        return total;
    }
}

To방법에 대한 일부 단위 테스트 :

[TestClass]
public class DecimalToRomanTest
{
    [TestMethod]
    public void Roman_1_I()
    {
        Assert.AreEqual("I", Roman.To(1));
    }

    [TestMethod]
    public void Roman_2_II()
    {
        Assert.AreEqual("II", Roman.To(2));
    }

    [TestMethod]
    public void Roman_3_III()
    {
        Assert.AreEqual("III", Roman.To(3));
    }

    [TestMethod]
    public void Roman_4_IV()
    {
        Assert.AreEqual("IV", Roman.To(4));
    }

    [TestMethod]
    public void Roman_5_V()
    {
        Assert.AreEqual("V", Roman.To(5));
    }

    [TestMethod]
    public void Roman_9_IX()
    {
        Assert.AreEqual("IX", Roman.To(9));
    }

    [TestMethod]
    public void Roman_10_X()
    {
        Assert.AreEqual("X", Roman.To(10));
    }

    [TestMethod]
    public void Roman_49_XLIX()
    {
        Assert.AreEqual("XLIX", Roman.To(49));
    }

    [TestMethod]
    public void Roman_50_L()
    {
        Assert.AreEqual("L", Roman.To(50));
    }

    [TestMethod]
    public void Roman_100_C()
    {
        Assert.AreEqual("C", Roman.To(100));
    }

    [TestMethod]
    public void Roman_400_CD()
    {
        Assert.AreEqual("CD", Roman.To(400));
    }

    [TestMethod]
    public void Roman_500_D()
    {
        Assert.AreEqual("D", Roman.To(500));
    }

    [TestMethod]
    public void Roman_900_CM()
    {
        Assert.AreEqual("CM", Roman.To(900));
    }

    [TestMethod]
    public void Roman_1000_M()
    {
        Assert.AreEqual("M", Roman.To(1000));
    }

    [TestMethod]
    public void Roman_11984_MMMMMMMMMMMCMLXXXIV()
    {
        Assert.AreEqual("MMMMMMMMMMMCMLXXXIV", Roman.To(11984));
    }
}

From방법에 대한 일부 단위 테스트 :

[TestClass]
public class RomanToDecimalTest
{
    [TestMethod]
    public void Roman_I_1()
    {
        Assert.AreEqual(1, Roman.From("I"));
    }

    [TestMethod]
    public void Roman_II_2()
    {
        Assert.AreEqual(2, Roman.From("II"));
    }

    [TestMethod]
    public void Roman_III_3()
    {
        Assert.AreEqual(3, Roman.From("III"));
    }

    [TestMethod]
    public void Roman_IV_4()
    {
        Assert.AreEqual(4, Roman.From("IV"));
    }

    [TestMethod]
    public void Roman_V_5()
    {
        Assert.AreEqual(5, Roman.From("V"));
    }

    [TestMethod]
    public void Roman_IX_9()
    {
        Assert.AreEqual(9, Roman.From("IX"));
    }

    [TestMethod]
    public void Roman_X_10()
    {
        Assert.AreEqual(10, Roman.From("X"));
    }

    [TestMethod]
    public void Roman_XLIX_49()
    {
        Assert.AreEqual(49, Roman.From("XLIX"));
    }

    [TestMethod]
    public void Roman_L_50()
    {
        Assert.AreEqual(50, Roman.From("L"));
    }

    [TestMethod]
    public void Roman_C_100()
    {
        Assert.AreEqual(100, Roman.From("C"));
    }

    [TestMethod]
    public void Roman_CD_400()
    {
        Assert.AreEqual(400, Roman.From("CD"));
    }

    [TestMethod]
    public void Roman_D_500()
    {
        Assert.AreEqual(500, Roman.From("D"));
    }

    [TestMethod]
    public void Roman_CM_900()
    {
        Assert.AreEqual(900, Roman.From("CM"));
    }

    [TestMethod]
    public void Roman_M_1000()
    {
        Assert.AreEqual(1000, Roman.From("M"));
    }

    [TestMethod]
    public void Roman_MMMMMMMMMMMCMLXXXIV_11984()
    {
        Assert.AreEqual(11984, Roman.From("MMMMMMMMMMMCMLXXXIV"));
    }
}

이것은 실제로 매우 재미있는 문제이며 dofactory.com 의 반대 예제 (로마 숫자를 십진수로 변환)를 기반으로 하면 패턴을 반전시키기가 매우 쉽고 아마도 약간 개선 할 수 있습니다. 이 코드는 1에서 3999999까지의 숫자를 지원합니다.

컨텍스트 클래스로 시작하여 파서의 I / O를 정의합니다.

public class Context
{
    private int _input;
    private string _output;

    public Context(int input)
    {
        this._input = input;
    }

    public int Input
    {
        get { return _input; }
        set { _input = value; }
    }

    public string Output
    {
        get { return _output; }
        set { _output = value; }
    }
}

그리고 구문 분석 작업을 정의하는 추상 표현식

public abstract class Expression
{
    public abstract void Interpret(Context value);
}

이제 수행 할 실제 작업을 정의하는 추상 터미널 표현식이 필요합니다.

public abstract class TerminalExpression : Expression
{
    public override void Interpret(Context value)
    {
        while (value.Input - 9 * Multiplier() >= 0)
        {
            value.Output += Nine();
            value.Input -= 9 * Multiplier();
        }
        while (value.Input - 5 * Multiplier() >= 0)
        {
            value.Output += Five();
            value.Input -= 5 * Multiplier();
        }
        while (value.Input - 4 * Multiplier() >= 0)
        {
            value.Output += Four();
            value.Input -= 4 * Multiplier();
        }
        while (value.Input - Multiplier() >= 0)
        {
            value.Output += One();
            value.Input -= Multiplier();
        }
    }

    public abstract string One();
    public abstract string Four();
    public abstract string Five();
    public abstract string Nine();
    public abstract int Multiplier();
}

그런 다음 로마 숫자의 동작을 정의하는 클래스 (로마 숫자가 문자 위에 막대를 사용하여 1000 번을 나타내는 소문자 규칙을 사용했습니다)

class MillionExpression : TerminalExpression
{
    public override string One() { return "m"; }
    public override string Four() { return ""; }
    public override string Five() { return ""; }
    public override string Nine() { return ""; }
    public override int Multiplier() { return 1000000; }
}
class HundredThousandExpression : TerminalExpression
{
    public override string One() { return "c"; }
    public override string Four() { return "cd"; }
    public override string Five() { return "d"; }
    public override string Nine() { return "cm"; }
    public override int Multiplier() { return 100000; }
}
class ThousandExpression : TerminalExpression
{
    public override string One() { return "M"; }
    public override string Four() { return "Mv"; }
    public override string Five() { return "v"; }
    public override string Nine() { return "Mx"; }
    public override int Multiplier() { return 1000; }
}
class HundredExpression : TerminalExpression
{
    public override string One() { return "C"; }
    public override string Four() { return "CD"; }
    public override string Five() { return "D"; }
    public override string Nine() { return "CM"; }
    public override int Multiplier() { return 100; }
}
class TenExpression : TerminalExpression
{
    public override string One() { return "X"; }
    public override string Four() { return "XL"; }
    public override string Five() { return "L"; }
    public override string Nine() { return "XC"; }
    public override int Multiplier() { return 10; }
}
class OneExpression : TerminalExpression
{
    public override string One() { return "I"; }
    public override string Four() { return "IV"; }
    public override string Five() { return "V"; }
    public override string Nine() { return "IX"; }
    public override int Multiplier() { return 1; }
}

거의 다 왔으니 파스 트리를 포함하는 Non-terminal 표현식이 필요합니다.

public class DecimalToRomaNumeralParser : Expression
{
    private List<Expression> expressionTree = new List<Expression>()
                                                  {
                                                      new MillionExpression(),
                                                      new HundredThousandExpression(),
                                                      new TenThousandExpression(),
                                                      new ThousandExpression(),
                                                      new HundredExpression(),
                                                      new TenExpression(),
                                                      new OneExpression()
                                                  };

    public override void Interpret(Context value)
    {
        foreach (Expression exp in expressionTree)
        {
             exp.Interpret(value);
        }
    }
}

마지막으로 클라이언트 코드 :

Context ctx = new Context(123);
var parser = new DecimalToRomaNumeralParser();
parser.Interpret(ctx);
Console.WriteLine(ctx.Output); // Outputs CXXIII

라이브 예 : http://rextester.com/rundotnet?code=JJBYW89744


한 줄에서 매우 효율적이지는 않지만 작동합니다.

public string RomanNumeralFrom(int number)
{
    return
        new string('I', number)
            .Replace(new string('I', 1000), "M")
            .Replace(new string('I', 900), "CM")
            .Replace(new string('I', 500), "D")
            .Replace(new string('I', 400), "CD")
            .Replace(new string('I', 100), "C")
            .Replace(new string('I', 90), "XC")
            .Replace(new string('I', 50), "L")
            .Replace(new string('I', 40), "XL")
            .Replace(new string('I', 10), "X")
            .Replace(new string('I', 9), "IX")
            .Replace(new string('I', 5), "V")
            .Replace(new string('I', 4), "IV");
}

바라건대 당신이 생각한 가장 간단한 해결책 :)

public string IntToRoman(int num) {    
    string[] thou={"","M","MM","MMM"};
    string[] hun={"","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"};
    string[] ten={"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"};
    string[] ones={"","I","II","III","IV","V","VI","VII","VIII","IX"};
    string roman="";        
    roman += thou[(int)(num/1000)%10];
    roman += hun[(int)(num/100)%10];
    roman += ten[(int)(num/10)%10];
    roman += ones[num%10];  

    return roman;
}   

다음은 DotNetSnippets 의 슬림 솔루션입니다 .

private string ToRomanNumber(int number)
{
    StringBuilder result = new StringBuilder();
    int[] digitsValues = { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000 };
    string[] romanDigits = { "I", "IV", "V", "IX", "X", "XL", "L", "XC", "C", "CD", "D", "CM", "M" };
    while (number > 0)
    {
        for (int i = digitsValues.Count() - 1; i >= 0; i--)
            if (number / digitsValues[i] >= 1)
            {
                number -= digitsValues[i];
                result.Append(romanDigits[i]);
                break;
            }
    }
    return result.ToString();
}

이 버전은 다른 버전처럼 "속임수"가 아닙니다. 모든 "기본" "구성 가능"번호를 사용하여 내부적으로 "기본"테이블을 생성합니다. 게으름을 위해 Tuple특수 클래스를 만드는 대신 s를 사용하고 있습니다. 당신은 C # 4.0이없는 경우 대체 할 수 Tuple<>KeyValuePair<>, Item1KeyItem2함께 Value.

static Tuple<IList<Tuple<string, int>>, int> GenerateBaseNumbers()
{
    const string letters = "IVXLCDM";

    var tuples = new List<Tuple<string, int>>();
    Tuple<string, int> subtractor = null;

    int num = 1;
    int maxNumber = 0;

    for (int i = 0; i < letters.Length; i++)
    {
        string currentLetter = letters[i].ToString();

        if (subtractor != null)
        {
            tuples.Add(Tuple.Create(subtractor.Item1 + currentLetter, num - subtractor.Item2));
        }

        tuples.Add(Tuple.Create(currentLetter, num));

        bool isEven = i % 2 == 0;

        if (isEven)
        {
            subtractor = tuples[tuples.Count - 1];
        }

        maxNumber += isEven ? num * 3 : num;
        num *= isEven ? 5 : 2;
    }

    return Tuple.Create((IList<Tuple<string, int>>)new ReadOnlyCollection<Tuple<string, int>>(tuples), maxNumber);
}

static readonly Tuple<IList<Tuple<string, int>>, int> RomanBaseNumbers = GenerateBaseNumbers();

static string FromNumberToRoman(int num)
{
    if (num <= 0 || num > RomanBaseNumbers.Item2)
    {
        throw new ArgumentOutOfRangeException();
    }

    StringBuilder sb = new StringBuilder();

    int i = RomanBaseNumbers.Item1.Count - 1;

    while (i >= 0)
    {
        var current = RomanBaseNumbers.Item1[i];

        if (num >= current.Item2)
        {
            sb.Append(current.Item1);
            num -= current.Item2;
        }
        else
        {
            i--;
        }
    }

    return sb.ToString();
}

static void Main(string[] args)
{
    for (int i = 1; i <= RomanBaseNumbers.Item2; i++)
    {
        var calc = FromNumberToRoman(i);

        Console.WriteLine("{1}", i, calc);
    }
}

너무 늦게, 아마 당신은 이미 이것을 풀었을 것입니다. 그러나 이것은 당신을 위해 트릭을 할 수있는 알고리즘입니다.

시작하기 전에 로마 문자에 대한 분석을 간단히 수행 할 수 있습니다. 알려진 ASCII 세트의 경우 0에서 4000 사이의 값만 지원됩니다. 넘어 가고 싶다면 자신 만의 로마 문자를 정의 할 수 있습니다.

시작하기 전에 위의 주어진 범위를 사용하여 로마 리터럴 (I, V, X, L, C, D 및 M)의 7 개 발생에서 로마 문자열을 형성 할 수 있음을 알고 있습니다.

따라서 다른 함수에서 계산 된 인덱스를 기반으로하는 간단한 조회 테이블부터 시작합니다. 알 수없는 인덱스는 공백 문자로 반환됩니다. 위에서 썼 듯이 필요할 때 추가 문자를 추가 할 수 있습니다.

    /// <summary>
    /// Helper method that looks up a given index to it's roman value.
    /// </summary>
    /// <param name="decimalValue"></param>
    /// <returns>The roman literal corresponding to it's index</returns>
    private char DecimalToRoman(int index)
    {
        switch (index)
        {
            case 1: return 'I';
            case 2: return 'V';
            case 3: return 'X';
            case 4: return 'L';
            case 5: return 'C';
            case 6: return 'D';
            case 7: return 'M';
            default: return ' ';
        }
    }

실제 변환은 여기에서 발생합니다.

    private string ConvertToRoman(string input)
    {
        int index = 0;
        string output = "";

        for (int i = 0; i < input.Length; i++)
        {
            //Some magic here, this formula will calculate the correct starting
            //index of the roman literal to find in the look-up table.
            //Since units, tens and hundreds (up to thousand) can be formed of
            //three roman literals, we need three indices for looking up the
            //correct roman literal.
            index = 2 * (input.Length - (i + 1)) + 1;

            char digit1 = DecimalToRoman(index);
            char digit2 = DecimalToRoman(index + 1);
            char digit3 = DecimalToRoman(index + 2);

            int originalValue = System.Convert.ToInt32(input[i] - '0');

            switch (originalValue)
            {
                case 1:
                case 2:
                case 3: for (int j = 0; j < originalValue; j++)
                        output += digit1.ToString();
                    break;
                case 4: output += digit1.ToString() + digit2.ToString();
                    break;
                case 5: output += digit2.ToString();
                    break;
                case 6:
                case 7:
                case 8: output += digit2.ToString();
                    for (int j = 0; j < originalValue - 5; j++)
                        output += digit1.ToString();
                    break;
                case 9: output += digit1.ToString() + digit3.ToString();
                    break;
            }              
        }
        return output;
    }

그게 다입니다. OO Designed 접근 방식을 더 찾고 있다면이 게시물 위에있는 답변을 수락하십시오. 이 접근 방식을 해결하는 방법에는 여러 가지가 있습니다.

편집 :이 솔루션은 속임수를 쓰지 않습니다 (로마 리터럴의 모든 발생을 검색). :)


Mosè Bottacini의 답변이 마음에 들었지만 재귀를 사용하면이 시나리오에서 몇 가지 부정적인 부작용이 있습니다. 하나는 가능한 스택 오버플로이므로 수의 상한을 제한합니다. 그렇습니다. 로마 숫자에서 엄청난 숫자가 얼마나 우스꽝스러워 보이는지 알지만 이것은 여전히 ​​결과를 얻기 위해 필요하지 않은 한계입니다.

또한 문자열은 변경할 수 없기 때문에 문자열 연결을 많이 사용하기 때문에 그의 버전은 메모리가 매우 비효율적입니다. 아래는 while 루프와 StringBuilder를 사용하여 그의 메서드를 수정 한 버전입니다. 내 버전은 실제로 더 성능이 뛰어나고 (우리가 밀리 초 미만 범위의 차이에 대해 이야기하고 있지만) 시스템 메모리에서 훨씬 쉬워야합니다.

public static string ToRomanNumeral(this int value)
{
    if (value < 0)
        throw new ArgumentOutOfRangeException("Please use a positive integer greater than zero.");

    StringBuilder sb = new StringBuilder();
    int remain = value;
    while (remain > 0)
    {
        if (remain >= 1000) { sb.Append("M"); remain -= 1000; }
        else if (remain >= 900) { sb.Append("CM"); remain -= 900; }
        else if (remain >= 500) { sb.Append("D"); remain -= 500; }
        else if (remain >= 400) { sb.Append("CD"); remain -= 400; }
        else if (remain >= 100) { sb.Append("C"); remain -= 100; }
        else if (remain >= 90) { sb.Append("XC"); remain -= 90; }
        else if (remain >= 50) { sb.Append("L"); remain -= 50; }
        else if (remain >= 40) { sb.Append("XL"); remain -= 40; }
        else if (remain >= 10) { sb.Append("X"); remain -= 10; }
        else if (remain >= 9) { sb.Append("IX"); remain -= 9; }
        else if (remain >= 5) { sb.Append("V"); remain -= 5; }
        else if (remain >= 4) { sb.Append("IV"); remain -= 4; }
        else if (remain >= 1) { sb.Append("I"); remain -= 1; }
        else throw new Exception("Unexpected error."); // <<-- shouldn't be possble to get here, but it ensures that we will never have an infinite loop (in case the computer is on crack that day).
    }

    return sb.ToString();
}

숫자에 해당하는 로마 숫자의 문자열 표현입니다.

    public static string ToRomanNumeral(this int number)
    {

        var retVal = new StringBuilder(5);
        var valueMap = new SortedDictionary<int, string>
                           {
                               { 1, "I" },
                               { 4, "IV" },
                               { 5, "V" },
                               { 9, "IX" },
                               { 10, "X" },
                               { 40, "XL" },
                               { 50, "L" },
                               { 90, "XC" },
                               { 100, "C" },
                               { 400, "CD" },
                               { 500, "D" },
                               { 900, "CM" },
                               { 1000, "M" },
                           };

        foreach (var kvp in valueMap.Reverse())
        {
            while (number >= kvp.Key)
            {
                number -= kvp.Key;
                retVal.Append(kvp.Value);
            }
        }

        return retVal.ToString();
    }

기존보다 비교적 간단한 방법을 제공 할 수 있습니다.

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public class Form1
{
    int[] indx = {
        1,
        2,
        3,
        4,
        5,
        10,
        50,
        100,
        500,
        1000
        // initialize array of integers 
    };
    string[] row = {
        "I",
        "II",
        "III",
        "IV",
        "V",
        "X",
        "L",
        "C",
        "D",
        "M"
        //Carasponding roman letters in for the numbers in the array
    };
        // integer to indicate the position index for link two arrays 
    int limit = 9;
        //string to store output
    string output = "";
    private void Button1_Click(System.Object sender, System.EventArgs e)
    {
        int num = 0;
        // stores the input 
        output = "";
        // clear output before processing
        num = Convert.ToInt32(txt1.Text);
        // get integer value from the textbox
        //Loop until the value became 0
        while (num > 0) {
            num = find(num);
            //call function for processing
        }
        txt2.Text = output;
        // display the output in text2
    }
    public int find(int Num)
    {
        int i = 0;
        // loop variable initialized with 0
        //Loop until the indx(i).value greater than or equal to num
        while (indx(i) <= Num) {
            i += 1;
        }
        // detemine the value of limit depends on the itetration
        if (i != 0) {
            limit = i - 1;
        } else {
            limit = 0;
        }
        output = output + row(limit);
        //row(limit) is appended with the output
        Num = Num - indx(limit);
        // calculate next num value
        return Num;
        //return num value for next itetration 
    }
}

나는 그것을 시도했고 내 솔루션은 다음과 같습니다.

public class RomanNumeral
{
    private readonly IDictionary<int, string> romanDictionary = new Dictionary<int, string> 
    {
        {1, "I"}, {5, "V"}, {10, "X"}, {50, "L"}, {100, "C"}, {500, "D"}, {1000, "M"}
    };

    private int factor = 1;

    public string Parse(int arabicNumber)
    {
        if (arabicNumber < 0) throw new ArgumentException();

        var romanNumerals = new List<string>();
        foreach (var number in arabicNumber.Split().Reverse())
        {
            romanNumerals.Insert(0, ToRoman(number));
            factor *= 10;
        }
        return romanNumerals.Concatenated();
    }

    private string ToRoman(int number)
    {
        if (number.In(4, 9)) return ToRoman(1) + ToRoman(number + 1);
        if (number.In(6, 7, 8)) return ToRoman(number - 1) + ToRoman(1);
        if (number.In(2, 3)) return ToRoman(1) + ToRoman(number - 1);
        if (number == 0) return string.Empty;
        return romanDictionary[number * factor];
    }
}

깔끔하고 빠르며 간단한 솔루션

function convertToRoman(num) {

  //Roman numerals to have <= 3 consecutive characters, the distances between deciaml values conform to this
  var decimalValue = [ 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 ];
  var romanNumeral = [ 'M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I' ];
  var num_cp = num; // copy the function parameter into num_cp
  var result = '';

  for (var i=0; i < decimalValue.length; i++){ //itarate through array of decimal values
      //iterate more to find values not explicitly provided in the decimalValue array
    while (decimalValue[i] <= num_cp){
      result += romanNumeral[i];
      num_cp -= decimalValue[i];
    }
  }
  return result;
}

convertToRoman(477);

하나 더 간단한 해결책. 내가 StringBuilder를 사용하는 성능을 약간 향상시키고 더 적은 키를 반복합니다 (물론 LINQ-where의 다른 사이트에서 추가 지연이 추가 될 수 있음).

public class ArabicToRomanConverter
{
    private static readonly Dictionary<int, string> _romanDictionary = new Dictionary<int, string>
    {
        {1000,"M"},
        {900,"CM"},
        {500,"D"},
        {400,"CD"},
        {100,"C"},
        {90,"XC"},
        {50,"L"},
        {40,"XL"},
        {10,"X"},
        {9,"IX"},
        {5,"V"},
        {4,"IV"},
        {1 ,"I"}
    };

    public ArabicToRomanConverter()
    {

    }

    public string Convert(int arabicNumber)
    {
        StringBuilder romanNumber = new StringBuilder();
        var keys = _romanDictionary.Keys.Where(k => arabicNumber >= k).ToList();
        for (int i = 0; i < keys.Count && arabicNumber > 0; i++)
        {
            int ckey = keys[i];
            int division = arabicNumber / ckey;
            if (division != 0)
            {
                for (int j = 0; j < division; j++)
                {
                    romanNumber.Append(_romanDictionary[ckey]);
                    arabicNumber -= ckey;
                }
            }
        }

        return romanNumber.ToString();
    }
}

"감산 표기법"의미 검사를 수행하는 솔루션

현재 솔루션은 "감산 표기법"에 대한 전체 규칙 집합을 완전히 충족하지 않습니다. "IIII"-> 불가능합니다. 각 솔루션의 결과는 4입니다. 또한 "CCCC", "VV", "IC", "IM"문자열도 유효하지 않습니다.

의미론을 확인하는 좋은 온라인 변환기는 https://www.romannumerals.org/converter입니다. 따라서 완전히 의미론을 확인하고 싶다면 훨씬 더 복잡합니다.

public class RomanNumerals
{

    private List<Tuple<char, ushort, char?[]>> _validNumerals = new List<Tuple<char, ushort, char?[]>>()
    {
        new Tuple<char, ushort, char?[]>('I', 1, new char? [] {'V', 'X'}),
        new Tuple<char, ushort, char?[]>('V', 5, null),
        new Tuple<char, ushort, char?[]>('X', 10, new char?[] {'L', 'C'}),
        new Tuple<char, ushort, char?[]>('L', 50, null),
        new Tuple<char, ushort, char?[]>('C', 100, new char? [] {'D', 'M'}),
        new Tuple<char, ushort, char?[]>('D', 500, null),
        new Tuple<char, ushort, char?[]>('M', 1000, new char? [] {null, null})
    };


    public int TranslateRomanNumeral(string input)
    {
        var inputList = input?.ToUpper().ToList();

        if (inputList == null || inputList.Any(x => _validNumerals.Select(t => t.Item1).Contains(x) == false))
        {
            throw new ArgumentException();
        }

        char? valForSubtraction = null;
        int result = 0;
        bool noAdding = false;
        int equalSum = 0;
        for (int i = 0; i < inputList.Count; i++)
        {
            var currentNumeral = _validNumerals.FirstOrDefault(s => s.Item1 == inputList[i]);
            var nextNumeral = i < inputList.Count - 1 ? _validNumerals.FirstOrDefault(s => s.Item1 == inputList[i + 1]) : null;
            bool currentIsDecimalPower = currentNumeral?.Item3?.Any() ?? false;

            if (nextNumeral != null)
            {
                // Syntax and Semantics checks
                if ((currentNumeral.Item2 < nextNumeral.Item2) && (currentIsDecimalPower == false || currentNumeral.Item3.Any(s => s == nextNumeral.Item1) == false) ||
                    (currentNumeral.Item2 == nextNumeral.Item2) && (currentIsDecimalPower == false || nextNumeral.Item1 == valForSubtraction) ||
                    (currentIsDecimalPower && result > 0 &&  ((nextNumeral.Item2 -currentNumeral.Item2) > result )) ||
                    (currentNumeral.Item2 > nextNumeral.Item2) && (nextNumeral.Item1 == valForSubtraction)

                    )
                {
                    throw new ArgumentException();
                }

                if (currentNumeral.Item2 == nextNumeral.Item2)
                {
                    equalSum += equalSum == 0 ? currentNumeral.Item2 + nextNumeral.Item2 : nextNumeral.Item2;
                    int? smallest = null;
                    var list = _validNumerals.Where(p => _validNumerals.FirstOrDefault(s => s.Item1 == currentNumeral.Item1).Item3.Any(s2 => s2 != null && s2 == p.Item1)).ToList();
                    if (list.Any())
                    {
                        smallest = list.Select(s3 => s3.Item2).ToList().Min();
                    }

                    // Another Semantics check
                    if (currentNumeral.Item3 != null && equalSum >= (smallest - currentNumeral.Item2))
                    {
                        throw new ArgumentException();
                    }

                    result += noAdding ? 0 : currentNumeral.Item2 + nextNumeral.Item2;
                    noAdding = !noAdding;
                    valForSubtraction = null;
                }
                else
                if (currentNumeral.Item2 < nextNumeral.Item2)
                {
                    equalSum = 0;
                    result += nextNumeral.Item2 - currentNumeral.Item2;
                    valForSubtraction = currentNumeral.Item1;
                    noAdding = true;
                }
                else 
                if (currentNumeral.Item2 > nextNumeral.Item2)
                {
                    equalSum = 0;
                    result += noAdding ? 0 : currentNumeral.Item2;
                    noAdding = false;

                    valForSubtraction = null;
                }
            }
            else
            {
                result += noAdding ? 0 : currentNumeral.Item2;
            }
        }
        return result;
    }
}

 public static int pairConversion(int dec, int lastNum, int lastDec)
    {
        if (lastNum > dec)
            return lastDec - dec;
        else return lastDec + dec;
    }

    public static int ConvertRomanNumtoInt(string strRomanValue)
    {
        var dec = 0;
        var lastNum = 0;
        foreach (var c in strRomanValue.Reverse())
        {
            switch (c)
            {
                case 'I':
                    dec = pairConversion(1, lastNum, dec);
                    lastNum = 1;
                    break;
                case 'V':
                    dec=pairConversion(5,lastNum, dec);
                    lastNum = 5;
                    break;
                case 'X':
                    dec = pairConversion(10, lastNum, dec);
                    lastNum = 10;
                    break;
                case 'L':
                    dec = pairConversion(50, lastNum, dec);
                    lastNum = 50;
                    break;
                case 'C':
                    dec = pairConversion(100, lastNum, dec);
                    lastNum = 100;
                    break;
                case 'D':
                    dec = pairConversion(500, lastNum, dec);
                    lastNum = 500;
                    break;
                case 'M':
                    dec = pairConversion(1000, lastNum, dec);
                    lastNum = 1000;
                    break;
            }
        }
        return dec;

    }

로마 숫자를 반대로하면 XIV와 같은 경우를 처리하는 것이 더 쉬울 것입니다. 코드는이 블로그 에서 참조 합니다.


namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Enter the number\n");
            int num = int.Parse(Console.ReadLine());
            ToRomanNumber tr = new ToRomanNumber();
            string opt=tr.ToRoman(num);
            Console.WriteLine(opt);
        }
    }
    class ToRomanNumber
    {
        string s = "";

        public string ToRoman(int number)
        {

            if ((number < 0) || (number > 3999))
            {
                s = s + "Invalid Input";
            }
            if (number < 1) return s;
            if (number >= 1000) { s = s + "M"; ToRoman(number - 1000);}
            if (number >= 900){ s = s + "CM";ToRoman(number - 900);}
            if (number >= 500){ s = s + "D"; ToRoman(number - 500);}
            if (number >= 400){ s = s + "CD"; ToRoman(number - 400);}
            if (number >= 100){ s = s + "C"; ToRoman(number - 100);}
            if (number >= 90){ s = s + "XC"; ToRoman(number - 90);}
            if (number >= 50){ s = s + "L";ToRoman(number - 50);}
            if (number >= 40){ s = s + "XL";ToRoman(number - 40);}
            if (number >= 10){ s = s + "X"; ToRoman(number - 10); }
            if (number >= 9) { s = s + "IX"; ToRoman(number - 9); }
            if (number >= 5) { s = s + "V"; ToRoman(number - 5); }
            if (number >= 4) { s = s + "IV"; ToRoman(number - 4); }
            if (number >= 1) { s = s + "I"; ToRoman(number - 1);}
            return s;
        }
    }
}

BrunoLM의 코드는 매우 간단하고 우아하지만 From (...) 함수는 소스가 유효한 로마 숫자인지 확인해야합니다.
이 같은

public static bool IsValidRomanNumber(string source) {
        bool result = true;

        string[] invalidCouples = { "VV", "LL", "DD", "VX", "VC", "VM", "LC", "LM", "DM", "IC", "IM", "XM" };

        foreach (string s in invalidCouples) {
            if (source.Contains(s)) {
                result = false;
                break;
            }
        }

        return result;
    }

        Random r = new Random();
        int[] arreglo = new int[100];
        for (int i=0; i<arreglo.Length;i++) {
            arreglo[i] = r.Next(1,1001);
        }

        for (int t = 0;t < arreglo.Length; t++)
        {
            if (arreglo[t] >= 1000)
            {
                Console.Write("M"); arreglo[t] -= 1000;
            }
            if (arreglo[t] >=900)
            {
                Console.Write("MC"); arreglo[t] -= 900;
            }
            if (arreglo[t] >= 500)
            {
                Console.Write("D"); arreglo[t] -= 500;
            }
            if (arreglo[t] >= 400)
            {
                Console.Write("CD"); arreglo[t] -= 400;
            }
            if (arreglo[t] >= 100) {
                Console.Write("C"); arreglo[t] -= 100;
            }
            if (arreglo[t] >= 90)
            {
                Console.Write("XC"); arreglo[t] -= 90;
            }
            if (arreglo[t] >= 50)
            {
                Console.Write("L"); arreglo[t] -= 50;
            }
            if (arreglo[t] >= 40)
            {
                Console.Write("XL"); arreglo[t] -= 40;
            }
            if (arreglo[t] >= 10)
            {
                Console.Write("X"); arreglo[t] -= 10;
            }
            if (arreglo[t] >= 9)
            {
                Console.Write("IX"); arreglo[t] -= 9;
            }
            if (arreglo[t] >= 5)
            {
                Console.Write("V"); arreglo[t] -= 5;
            }
            if (arreglo[t] >= 4)
            {
                Console.Write("IV"); arreglo[t] -= 4;
            }
            if (arreglo[t] >= 1)
            {
                Console.Write("I"); arreglo[t] -= 1;
            }

            Console.WriteLine();

        }
        Console.ReadKey();    

해결책은 길지만 초보자에게는 이해하기 쉽습니다. 3000까지 처리

namespace RomansTranslator
{
    using System;
    using System.Collections.Generic;
    /// <summary>
    /// Accepts a number (between 1 and 3000) and prints its Roman equivalent.
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            string number = string.Empty;
            Console.Write("Enter the Numeric number : ");
            number = Console.ReadLine();
            if (IsValid(number)) // Validates the input
            {
                string roman = ConvertToRoman(number);
                Console.WriteLine("Roman Number is " + roman);
            }
            else
            {
                Console.WriteLine("Invalid Number");
            }
            Console.ReadKey();
        }

        private static string ConvertToRoman(string numberString)
        {
            string romanValue = string.Empty;
            int number = Convert.ToInt32(numberString);
            if (number >= 1)
            {
                // Loop through each roman character from highest 
                foreach (int item in RomanDictionary().Keys)
                {
                    while (number >= item)
                    {
                        romanValue = romanValue + RomanString(item);
                        number -= item;
                    }
                }
            }
            return romanValue;
        }

        /// <summary>
        /// Returns Roman Equvalent
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        private static string RomanString(int n)
        {
            string romanString = string.Empty;
            romanString = RomanDictionary()[n].ToString();
            return romanString;
        }

        /// <summary>
        /// List of Roman Characters 
        /// </summary>
        /// <returns></returns>
        private static Dictionary<int, string> RomanDictionary()
        {

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


        /// <summary>
        /// Validates the Input
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private static bool IsValid(string input)
        {
            int value = 0;
            bool isValid = false;
            if (int.TryParse(input, out value))
            {
                if (value <= 3000)
                {
                    isValid = true;
                }
            }
            return isValid;
        }
    }
}

다음은 @Cammilius에서 C #으로 변환 된 버전입니다. 낮은 숫자로 저를 위해 작동하며 이는 제 사용 사례에 필요한 전부입니다.

public String convertToRoman(int num)
{    
    //Roman numerals to have <= 3 consecutive characters, the distances between deciaml values conform to this
    int[] decimalValue = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
    string[] romanNumeral = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
    int num_cp = num; // copy the function parameter into num_cp
    String result = "";

    for (var i = 0; i < decimalValue.Length; i = i + 1)
    { //itarate through array of decimal values
        //iterate more to find values not explicitly provided in the decimalValue array
        while (decimalValue[i] <= num_cp)
        {
            result = result + romanNumeral[i];
            num_cp = num_cp - decimalValue[i];
        }
    }
    return result;
}

public static String convert(int num)
{
    String[] charsArray  = {"I", "IV", "V", "IX", "X", "XL", "L", "XC","C","CD","D","CM","M" };
    int[] charValuesArray = {1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000};

    String resultString = "";
    int temp = num;
    int [] resultValues = new int[13];
    // Generate an array which "char" occurances count
    for(int i = 12 ; i >= 0 ; i--)
    {
        if((temp / charValuesArray[i]) > 0)
        {
            resultValues[i] = temp/charValuesArray[i];
            temp = temp % charValuesArray[i];
        }
    }
    // Print them if not occured do not print
    for(int j = 12 ; j >= 0 ; j--)
    {
        for(int k = 0 ; k < resultValues[j]; k++)
        {
            resultString+= charsArray[j];
        }
    }
    return resultString;

}

이 문제가 흥미 롭다고 생각했는데, 이것이 제가 취한 것입니다.

그것은 해야한다 (희망) overscored 문자의 상한의 숫자까지 취급한다. 다른 규칙을 추가하는 것은 새 밴드를 구성하고 ConfigureNext체인을 조정하는 문제 일뿐 입니다.

NumeralGenerator.cs

public static class NumeralGenerator
{
    private static readonly INumeralBand RootNumeralBand = ConfigureMapping();

    private static INumeralBand ConfigureMapping()
    {
        var unitBand = new FinalBand(1, "I");

        var fiveBand = new NumeralBand(5, "V", unitBand);
        var tenBand = new NumeralBand(10, "X", unitBand);
        var fiftyBand = new NumeralBand(50, "L", tenBand);
        var hundredBand = new NumeralBand(100, "C", tenBand);
        var fiveHundredBand = new NumeralBand(500, "D", hundredBand);
        var thousandBand = new NumeralBand(1000, "M", hundredBand);

        var thousandUnitBand = new NumeralBand(1000, "I\u0305", thousandBand);

        var fiveThousandBand = new NumeralBand(5000, "V\u0305", thousandUnitBand);
        var tenThousandBand = new NumeralBand(10000, "X\u0305", thousandUnitBand);
        var fiftyThousandBand = new NumeralBand(50000, "L\u0305", tenThousandBand);
        var hundredThousandBand = new NumeralBand(100000, "C\u0305", tenThousandBand);
        var fiveHundredThousandBand = new NumeralBand(500000, "D\u0305", hundredThousandBand);
        var millionBand = new NumeralBand(1000000, "M\u0305", hundredThousandBand);

        millionBand
            .ConfigureNext(fiveHundredThousandBand)
            .ConfigureNext(hundredThousandBand)
            .ConfigureNext(fiftyThousandBand)
            .ConfigureNext(tenThousandBand)
            .ConfigureNext(fiveThousandBand)
            .ConfigureNext(thousandBand)
            .ConfigureNext(fiveHundredBand)
            .ConfigureNext(hundredBand)
            .ConfigureNext(fiftyBand)
            .ConfigureNext(tenBand)
            .ConfigureNext(fiveBand)
            .ConfigureNext(unitBand);

        return millionBand;
    }

    public static string ToNumeral(int number)
    {
        var numerals = new StringBuilder();

        RootNumeralBand.Process(number, numerals);

        return numerals.ToString();
    }
}

INumeralBand.cs

public interface INumeralBand
{
    int Value { get; }
    string Numeral { get; }

    void Process(int number, StringBuilder numerals);
}

NumeralBand.cs

public class NumeralBand : INumeralBand
{
    private readonly INumeralBand _negatedBy;
    private INumeralBand _nextBand;

    public NumeralBand(int value, string numeral, INumeralBand negatedBy)
    {
        _negatedBy = negatedBy;

        Value = value;
        Numeral = numeral;
    }

    public int Value { get; }
    public string Numeral { get; }

    public void Process(int number, StringBuilder numerals)
    {
        if (ShouldNegateAndStop(number))
        {
            numerals.Append(NegatedNumeral);
            return;
        }

        var numeralCount = Math.Abs(number / Value);
        var remainder = number % Value;

        numerals.Append(string.Concat(Enumerable.Range(1, numeralCount).Select(x => Numeral)));

        if (ShouldNegateAndContinue(remainder))
        {
            NegateAndContinue(numerals, remainder);
            return;
        }

        if (remainder > 0)
            _nextBand.Process(remainder, numerals);
    }

    private string NegatedNumeral => $"{_negatedBy.Numeral}{Numeral}";

    private bool ShouldNegateAndStop(int number) => number == Value - _negatedBy.Value;
    private bool ShouldNegateAndContinue(int number) => number >= Value - _negatedBy.Value;

    private void NegateAndContinue(StringBuilder stringBuilder, int remainder)
    {
        stringBuilder.Append(NegatedNumeral);
        remainder = remainder % (Value - _negatedBy.Value);

        _nextBand.Process(remainder, stringBuilder);
    }

    public T ConfigureNext<T>(T nextBand) where T : INumeralBand
    {
        _nextBand = nextBand;

        return nextBand;
    }
}

FinalBand.cs

public class FinalBand : INumeralBand
{
    public FinalBand(int value, string numeral)
    {
        Value = value;
        Numeral = numeral;
    }

    public int Value { get; }
    public string Numeral { get; }

    public void Process(int number, StringBuilder numerals)
    {
        numerals.Append(new string(Numeral[0], number));
    }
}

테스트 :

FinalBandTests.cs

public class FinalBandTests
{
    [Theory]
    [InlineData(1, "I")]
    [InlineData(2, "II")]
    [InlineData(3, "III")]
    [InlineData(4, "IIII")]
    public void Process(int number, string expected)
    {
        var stringBuilder = new StringBuilder();

        var numeralBand = new FinalBand(1, "I");
        numeralBand.Process(number, stringBuilder);

        Assert.Equal(expected, stringBuilder.ToString());
    }
}

NumeralBandTests.cs

public class NumeralBandTests
{
    private Mock<INumeralBand> _nextBand;
    private Mock<INumeralBand> _negatedBy;

    private StringBuilder _stringBuilder;

    public NumeralBandTests()
    {
        _stringBuilder = new StringBuilder();

        _nextBand = new Mock<INumeralBand>();
        _negatedBy = new Mock<INumeralBand>();
    }

    [Fact]
    public void Process_NegateAndStop()
    {
        var numeral = new NumeralBand(10, "X", _negatedBy.Object);

        _negatedBy.Setup(x => x.Value).Returns(1);
        _negatedBy.Setup(x => x.Numeral).Returns("I");

        numeral.Process(9, _stringBuilder);

        Assert.Equal("IX", _stringBuilder.ToString());
        _nextBand.Verify(x => x.Process(It.IsAny<int>(), It.IsAny<StringBuilder>()), Times.Never);
    }

    [Fact]
    public void Process_Exact()
    {
        var numeral = new NumeralBand(10, "X", _negatedBy.Object);

        _negatedBy.Setup(x => x.Value).Returns(1);
        _negatedBy.Setup(x => x.Numeral).Returns("I");

        numeral.Process(10, _stringBuilder);

        Assert.Equal("X", _stringBuilder.ToString());
        _nextBand.Verify(x => x.Process(It.IsAny<int>(), It.IsAny<StringBuilder>()), Times.Never);
    }

    [Fact]
    public void Process_NegateAndContinue()
    {
        var numeral = new NumeralBand(50, "L", _negatedBy.Object);
        numeral.ConfigureNext(_nextBand.Object);

        _negatedBy.Setup(x => x.Value).Returns(10);
        _negatedBy.Setup(x => x.Numeral).Returns("X");

        numeral.Process(54, _stringBuilder);

        Assert.Equal("L", _stringBuilder.ToString());
        _nextBand.Verify(x => x.Process(4, _stringBuilder), Times.Once);
    }
}

NumeralGeneratorTests.cs

public class NumeralGeneratorTests
{
    private readonly ITestOutputHelper _output;

    public NumeralGeneratorTests(ITestOutputHelper output)
    {
        _output = output;
    }

    [Theory]
    [InlineData(1, "I")]
    [InlineData(2, "II")]
    [InlineData(3, "III")]
    [InlineData(4, "IV")]
    [InlineData(5, "V")]
    [InlineData(6, "VI")]
    [InlineData(7, "VII")]
    [InlineData(8, "VIII")]
    [InlineData(9, "IX")]
    [InlineData(10, "X")]
    [InlineData(11, "XI")]
    [InlineData(15, "XV")]
    [InlineData(1490, "MCDXC")]
    [InlineData(1480, "MCDLXXX")]
    [InlineData(1580, "MDLXXX")]
    [InlineData(1590, "MDXC")]
    [InlineData(1594, "MDXCIV")]
    [InlineData(1294, "MCCXCIV")]
    [InlineData(3999, "MMMCMXCIX")]
    [InlineData(4000, "I\u0305V\u0305")]
    [InlineData(4001, "I\u0305V\u0305I")]
    [InlineData(5002, "V\u0305II")]
    [InlineData(10000, "X\u0305")]
    [InlineData(15000, "X\u0305V\u0305")]
    [InlineData(15494, "X\u0305V\u0305CDXCIV")]
    [InlineData(2468523, "M\u0305M\u0305C\u0305D\u0305L\u0305X\u0305V\u0305MMMDXXIII")]
    public void ToNumeral(int number, string expected)
    {
        var sw = Stopwatch.StartNew();
        var actual = NumeralGenerator.ToNumeral(number);
        sw.Stop();

        _output.WriteLine(sw.ElapsedMilliseconds.ToString());

        Assert.Equal(expected, actual);
    }
}

@Backwards_Dave 최대 수에 이르는 솔루션을 원했습니다. 여기에 있습니다.

public class ConvertDecimalNumberToRomanNumberType
{
    public class RomanNumberType
    {
        public string RomanNumber;
        public int RomanNumberValue;
    }

    public List<RomanNumberType> RomanNumbers;

    public void Initialize()
    {
        RomanNumbers = new List<RomanNumberType>();

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "M", RomanNumberValue = 1000 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "CM", RomanNumberValue = 900 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "D", RomanNumberValue = 500 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "CD", RomanNumberValue = 400 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "C", RomanNumberValue = 100 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "XC", RomanNumberValue = 90 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "L", RomanNumberValue = 50 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "XL", RomanNumberValue = 40 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "X", RomanNumberValue = 10 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "IX", RomanNumberValue = 9 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "V", RomanNumberValue = 5 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "IV", RomanNumberValue = 4 });

        RomanNumbers.Add(new RomanNumberType() { RomanNumber = "I", RomanNumberValue = 1 });
    }

    public string ConvertDecimalNumberToRomanNumber(int GetConvertDecimalNumberToRomanNumber)
    {
        string
            FunctionResult
            , CurrentRomanNumber = "";

        int
            FunctionGet = GetConvertDecimalNumberToRomanNumber
            , DecimalNumberRemaining = FunctionGet;

        foreach(RomanNumberType RomanNumber in RomanNumbers)
            while(RomanNumber.RomanNumberValue <= DecimalNumberRemaining)
            {
                DecimalNumberRemaining -= RomanNumber.RomanNumberValue;

                CurrentRomanNumber += RomanNumber.RomanNumber;
            }

        FunctionResult = CurrentRomanNumber;

        return FunctionResult;
    }
}

사용법 :

ConvertDecimalNumberToRomanNumberType ConvertDecimalNumberToRomanNumberObject = new ConvertDecimalNumberToRomanNumberType();

ConvertDecimalNumberToRomanNumberObject.Initialize();

var SomeVariable = ConvertDecimalNumberToRomanNumberObject.ConvertDecimalNumberToRomanNumber(1999);

First create list of Tuples which contains numbers and corresponds.
Then a method/loops to iterate and return result.

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


 public string ToConvert(decimal num)
            { 
                 data = data.OrderByDescending(o => o.Item1).ToList(); 
                List<Tuple<int, string>> subData = data.Where(w => w.Item1 <= num).ToList();
                StringBuilder sb = new StringBuilder();
                foreach (var item in subData)
                {
                    if (num >= item.Item1)
                    {
                        while (num >= item.Item1)
                        {
                            num -= item.Item1;
                            sb.Append(item.Item2.ToUpper());
                        }
                    }
                } 
                return sb.ToString();
            }

확장을 염두에두고 이해하기 쉽게 만들어졌지만 아마도 가장 빠른 방법은 아닐 것입니다. 나는 인터뷰 테스트의 일부로 (매우 사기가 심한) 이것을 완료하고 싶었지만 문제를 해결하려면 먼저 문제를 이해해야합니다.

모든 숫자를 입력해야하며 여기에서 확인할 수 있습니다. https://www.calculateme.com/roman-numerals/from-roman

        static void Main(string[] args)
    {

        CalculateRomanNumerals(1674);
    }

    private static void CalculateRomanNumerals(int integerInput)
    {
        foreach (var item in Enum.GetValues(typeof(RomanNumerals)).Cast<int>().Reverse())
        {
            integerInput = ProcessNumber(integerInput, item);
        }

        Console.ReadKey();
    }

    private static int ProcessNumber(int input, int number)
    {
        while (input >= number)
        {
            input -= number;
            Console.Write((RomanNumerals)number);
        }

        return input;
    }

    enum RomanNumerals : int
    {
        I = 1,
        IV = 4,
        V = 5,
        IX = 9,
        X = 10,
        L = 50,
        XC = 90,
        C = 100,
        CD = 400,
        D = 500,
        CM = 900,
        M = 1000
    }

참조 URL : https://stackoverflow.com/questions/7040289/converting-integers-to-roman-numerals

반응형