visual romanos romano que pseint programa para número numeros naturales lea flujo escriba equivalente entre diagrama convertir calcule arabigos algoritmo c# c#-3.0 roman-numerals

c# - que - Convertir números enteros a números romanos



escriba un algoritmo que lea un número entre 1 y 999 y calcule su equivalente en romano (22)

Estoy tratando de escribir una función que convierte números a números romanos. Este es mi código hasta ahora; sin embargo, solo funciona con números menores a 400. ¿Existe una forma rápida y fácil de hacer esta conversión, o extender mi código existente para que maneje todos los casos? Gracias de antemano por cualquier ayuda.

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(); }


Aquí está la versión de @Cammilius convertida a C # - funciona para mí en números bajos, que es todo lo que necesito para mi caso de uso.

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; }


Aquí hay un algoritmo mucho más simple: perdóneme, no sé C #, así que estoy escribiendo esto en JavaScript, pero debería aplicarse el mismo algoritmo (y he comentado para que pueda comprender el algoritmo):

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


Aquí hay una solución delgada de 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(); }


El código de BrunoLM me parece muy simple y elegante, pero la función Desde (...) realmente necesita verificar si la fuente es un número romano válido.
Algo como esto

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; }


En 1 línea, no muy eficiente pero funciona:

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"); }


En realidad, este es un problema bastante divertido, y basado en el ejemplo inverso de dofactory.com (convertir los números romanos en decimales) es bastante fácil revertir el patrón, y quizás mejorarlo un poco. Este código soportará números del 1 al 3999999.

Comience con una clase de contexto, esto define la E / S del analizador

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; } } }

Y una expresión abstracta, que define la operación de análisis.

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

Ahora, necesita una expresión terminal abstracta, que define la operación real que se realizará:

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(); }

Luego, las clases que definen el comportamiento de los números romanos (nota, he usado la convención de minúsculas donde los números romanos usan una barra sobre la letra para indicar 1000 veces)

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; } }

Casi allí, necesitamos una expresión no terminal que contenga el árbol de análisis:

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); } } }

Por último, el código del cliente:

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

Ejemplo en vivo: http://rextester.com/rundotnet?code=JJBYW89744


Esta versión no "hace trampa" como otras: genera internamente la tabla "base" con todos los números "base" "compostables". Para la pereza, estoy usando Tuple s, en lugar de crear clases especializadas. Si no tiene C # 4.0, puede reemplazar Tuple<> con KeyValuePair<> , Item1 con Key y Item2 con 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); } }


He creado esta clase que hace 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" }, { 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; } }

Algunas pruebas unitarias para el método 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)); } }

Algunas pruebas unitarias para el método de:

[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")); } }


La solución es larga, pero fácil de entender para un principiante. Procesa hasta 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; } } }


Lo intenté y mi solución se parece a esto:

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]; } }


Muy tarde, probablemente ya hayas resuelto esto, sin embargo, este es un algoritmo que también puede hacer el truco por ti.

Antes de comenzar, simplemente podrías hacer el análisis de los literales romanos. Para el conjunto ASCII conocido, solo se admiten valores entre 0 y 4000. Si te gusta ir más allá, entonces podrías definir tu propio literal romano.

Antes de comenzar, sabemos que con el rango anterior, podemos formar una cadena romana a partir de siete apariciones de literales romanos (I, V, X, L, C, D y M).

Por lo tanto, comenzamos con una tabla de consulta simple, basada en índices que se calculan en otra función. Los índices desconocidos se devuelven como un carácter de espacio en blanco. Como escribí anteriormente, uno podría agregar caracteres adicionales cuando sea necesario:

/// <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 '' ''; } }

La conversión real sucederá aquí:

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; }

Eso es. Si busca más enfoques diseñados por OO, acepte las respuestas sobre esta publicación. Hay muchas formas de resolver este enfoque.

EDITAR: Tenga en cuenta que esta solución no hace trampa (solo busca todas las apariciones de literales romanos) :)


Prueba esto, simple y compacto:

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"); }


Puedo proporcionar un método que es comparativamente más simple que el existente

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 } }


Si bien me gustó la respuesta de Mosè Bottacini, el uso de recursión tiene un par de efectos secundarios negativos en este escenario. Uno es el posible desbordamiento de pila, por lo tanto, su limitación del límite superior del número. Si bien, sí, me doy cuenta de lo ridículo que es un número enorme en números romanos, esto sigue siendo una limitación que no es necesaria para lograr el resultado.

Además, dado que las cadenas son inmutables, su versión será muy ineficiente en memoria, debido al gran uso de la concatenación de cadenas. A continuación se muestra mi versión modificada de su método, utilizando solo un bucle while y un StringBuilder. Mi versión debería ser más eficaz (aunque estamos hablando de diferencias en el rango de submilisegundos) y mucho más fácil en la memoria del sistema.

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(); }


Una solución limpia, rápida y directa.

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);


Esperemos que la solución más simple que hayas pensado :)

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; }


Pensé que este problema era interesante, esta fue mi opinión sobre él.

Se debe (con suerte) frente a los números hasta el límite superior de caracteres overscored. Agregar cualquier otra convención debería ser solo cuestión de configurar nuevas bandas y ajustar la ConfigureNextcadena.

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)); } }

Los exámenes:

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); } }


Una solución más directa. Intentando mejorar ligeramente el rendimiento que uso StringBuilder, iterar a través de menos claves (uno en el otro sitio, por supuesto, LINQ-donde podría agregar un retraso adicional)

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(); } }


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; }


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();


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; }

Sería más fácil si invierte los números romanos para manejar el caso como XIV. El código es referido desde este blog .


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; } } }