Decimal to Factorial number system - Extension functions
Inspired by the Decimal to Factorial and Back kata.
In that kata the task was to implement two functions, one of which should convert a number in base 10 into the corresponding represnetation in the factorial number system.
The factorial number system is a non-standard positional numeral system using factorials.
Read more on Wikipedia
This is usually a good use case for Extension functions in Kotlin.
Task
Extend the Kotlin Long class to include a method that converts a Long to its string representation in the factorial number system.
- Create an extension function for the Long class called toFactorialString. It should return a String that represents the number in the factorial number system.
- If the number is zero, the function should return "0".
Example:
36288000L.toFactorialString() // Should return "A0000000000"
463L.toFactorialString() // Should return "341010"
Note:
- The given numbers are always positive
- The function should be optimized for performance.
package solution
val factorialCache = mutableMapOf(0L to 1L)
val digitToChar = (0..9).map { it to it.toString().first() } + (10..35).map { it to ('A' + it - 10) }
fun Long.factorial(): Long = factorialCache.getOrPut(this) { this * (this - 1).factorial() }
// Extension function to convert Long to factorial string
fun Long.toFactorialString(): String {
var num = this
val digits = generateSequence(0) { it + 1 }
.takeWhile { num > 0 }
.map {
val remainder = num % (it + 1)
num /= (it + 1)
remainder
}
.toList()
.reversed()
.joinToString("") { digitToChar[it.toInt()].second.toString() }
return digits.ifEmpty { "0" }
}
package solution
import org.junit.Test
import kotlin.test.assertEquals
class FactorialConversionTest {
@Test
fun testToFactorialString() {
assertEquals("A0000000000", 36288000L.toFactorialString())
assertEquals("341010", 463L.toFactorialString())
assertEquals("0", 0L.toFactorialString())
assertEquals("10", 1L.toFactorialString())
assertEquals("4041000", 2982L.toFactorialString())
assertEquals("341010", 463L.toFactorialString())
assertEquals("76A0000021000", 3628800054L.toFactorialString())
assertEquals("27A0533231100", 1273928000L.toFactorialString())
assertEquals("140200", 220L.toFactorialString())
assertEquals("5301133210", 1936295L.toFactorialString())
assertEquals("204365543010", 81440635L.toFactorialString())
assertEquals("40721200210", 14808485L.toFactorialString())
assertEquals("4411210", 3395L.toFactorialString())
assertEquals("33100", 92L.toFactorialString())
assertEquals("6431110", 4881L.toFactorialString())
assertEquals("424400000", 174720L.toFactorialString())
assertEquals("11102210", 5897L.toFactorialString())
assertEquals("2410110", 1947L.toFactorialString())
assertEquals("4303332200", 1575088L.toFactorialString())
assertEquals("115113100", 49124L.toFactorialString())
assertEquals("25742343110", 9376317L.toFactorialString())
assertEquals("332210", 449L.toFactorialString())
assertEquals("42200", 112L.toFactorialString())
assertEquals("145123110", 64269L.toFactorialString())
assertEquals("18515001110", 6742089L.toFactorialString())
assertEquals("218474232200", 86565208L.toFactorialString())
assertEquals("3929024133200", 1806792694L.toFactorialString())
assertEquals("35576140110", 12942219L.toFactorialString())
assertEquals("311E55B5544150121110", 371993326789901217L.toFactorialString())
}
}
a kotlin more idiomatic way and with Long instead of Int