Swift Code Kata: Roman Numerals

Create the first 100 roman numerals and turn them back into integers

import Foundation

extension Int {
    func times(_ text: String) -> String {
        (0..<self).reduce(""){ e, _ in e + text }
    }
}

let digits = [
    ("I", "V", "X"),
    ("X", "L", "C"),
    ("C", "D", "M")
]

var exchangeRules: ((l:String, m:String, h:String)) -> [(Int, String, String)] = { r in
    [
        (10, r.l,     r.h),
        ( 9, r.l, r.l+r.h),
        ( 5, r.l,     r.m),
        ( 4, r.l, r.l+r.m)
    ]
}

func roman(for n:Int, digits: [(String, String, String)] = digits) -> String {
    digits
        .reduce(n.times("I")) {
            exchangeRules($1)
                .reduce($0) {
                    $0.replacingOccurrences(of: $1.0.times($1.1), with: $1.2)
        }
    }
}

func from(roman: String, digits: [(String, String, String)] = digits) -> Int {
    digits
        .reversed()
        .reduce (roman) {
            exchangeRules($1)
                .reversed()
                .reduce($0) {
                    $0.replacingOccurrences(of: $1.2, with: $1.0.times($1.1))
            }
    }.count
}

// --- Run ---

let romans = (1...100).map { roman(for: $0) }
let ints = romans.map { from(roman: $0) }
(zip(ints, romans)).forEach { x in
    print(x)
}

Discussion

Please feel free to discuss this article.