Kata - dado un numero entero devolver el equivalente en numero romano.

Problema

Crea una función que tome un entero positivo entre 1 y 3999 (ambos incluidos) como parámetro y devuelva una cadena que contenga la representación en números romanos de ese entero.

Los números romanos modernos se escriben expresando cada dígito por separado, comenzando con el dígito más a la izquierda y omitiendo cualquier dígito con un valor de cero. En números romanos, 1990 se representa como: 1000=M, 900=CM, 90=XC; lo que resulta en MCMXC. 2008 se escribe como 2000=MM, 8=VIII; o MMVIII. 1666 utiliza cada símbolo romano en orden descendente: MDCLXVI.

Ejemplo

solution(1000); // should return 'M'

Ayuda

Symbol    Value
I          1
V          5
X          10
L          50
C          100
D          500
M          1,000

Mas informacion http://en.wikipedia.org/wiki/Roman_numerals

Solucion

package kata

func Solution(number int) string {
latinNumbers := [13]int{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}
	romanNumbers := [13]string{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}
	originalNum := number
	var result string
	for index, valueLatin := range latinNumbers {
		for originalNum >= valueLatin {
			result += romanNumbers[index]
			originalNum -= valueLatin
		}
	}
	return result
}
  1. Preparacion de datos:
  • Creamos dos arrays cada elemento en latinNumbers corresponde al valor numerico en el sistema arbigo
  • Los elementos en _romanNumbers corresponden al valor numerico en romano.
  • Cada una de las posiciones corresponden entre si al mismo valor, ejemplo:
    latinNumbers[0] = 1000
      romanNumbers[0] = "M"
    
  • Es importante que el array este ordenado de mayor a menor ya que cuando hagamos el recorrido vamos a ir revisando si el numero que nos pasen es igual a mayor al primero elemento del array latinNumbers, de no ser asi continuara con el siguiente. Entonces si nos mandan el numero 1000 veremos si es mayor o igual a latinNumbers[0] que es 1000, como esto es verdadero le haremos un append a la variable result del numero romano que corresponda al mismo indice como en este caso empieza de mayor a menor, la posicion 0 en romanNumbers[0] es “M”, por lo que el resultado final sera result = “M” ,luego de la asignacion restamos el valor de latinNumbers[0] al numero que nos pasaron,para que en la siguiente iteracion no siga con los mismos valores y haga comparaciones diferentes.
  1. Variables iniciales:
  • originalNum se inicializa con el numero arabigo que nos pasan por parametro, podrias usar directamente el del parametro.
  • result se inicializa como una cadena vacia que contendra la representacion en numeros romanos.
  1. Bucle externo (for key, valueLatin := range latinNumbers):
  • El bucle exterior itera a traves de latinNumbers donde index es el indice actual y valueLatin el valor en numero arabigo que se va a considerar para la conversion.
  1. Bucle interno (for originalNum >= valueLatin):
  • El bucle interno, anidado dentro del bucle exterior, compara el número arábigo original (originalNum) con el valor numérico (valueLatin) correspondiente en latinNumbers.
  • Si originalNum es mayor o igual a valueLatin, significa que todavía podemos aplicar esa regla romana sin exceder el valor numérico original. Por ejemplo si nos mandan el numero 2000 para convertirlo a romano que seria “MM”, lo que hace este blucle es preguntarse, originalNum(2000) es mayor o igual a valueLatin(el value es 1000 porque estamos en la primer iteracion)? Si la respuesta es true agrega el valor que este en el mismo indice en romanNumbers a result en este caso como es la primer iteracion seria el indice 0 romanNumbers[0]_(que seria “M”), Luego le resta el numero arabigo al original que era 2000 y ahora nos queda en 1000, vuelve al loop interno y se vuelve a hacer la misma pregunta , ahora originalNumber no es mayor pero es igual por lo que vuelve a entrar y hace el mismo procedimiento, aun se encuentra sobre el indice 0, ya que el blucle exterio aun no se fue ejecutado nuevamente.Una vez que originalNum no sea capaz de entrar a la comparacion originalNum >= valueLatin por el indice 0, se ejecutara el bucle exterior pero esta vez con el indice 1.

En resumen, el bucle anidado garantiza que se apliquen las reglas romanas en el orden correcto y sin duplicaciones, lo que da como resultado una conversión precisa de números arábigos a números romanos. El bucle interno se repite para cada regla romana, y cada una se aplica solo si es válida para el valor actual de originalNum.

Porque usamos dos array en vez de un map?

La respuesta mas simple es que necesitamos que en la iteracion se respete el orden de mayor a menor,los map al ser iterados no respetan este orden sino que dan los resultados de manera aleatoria.

Porque usamos array en vez de slice?

En términos de rendimiento, los arrays en Go generalmente pueden ser más eficientes que los slices en situaciones específicas. Esto se debe a que los arrays tienen un tamaño fijo y, por lo tanto, el tamaño de la memoria se asigna en tiempo de compilación, lo que puede ser más eficiente en comparación con la asignación dinámica de memoria que se realiza con los slices.