我想将Swift中的一个整数
Integer
转换为罗马数字String
,有什么建议吗?Integer
转换为罗马数字String
,有什么建议吗?可以编写一个与下面所见类似的Int
扩展。
请注意:此代码将对小于一的数字返回“”。虽然在罗马数字中这可能是可以接受的(零不存在),但您可能希望在自己的实现中以不同的方式处理此问题。
extension Int {
var romanNumeral: String {
var integerValue = self
// Roman numerals cannot be represented in integers greater than 3999
if self >= 4000 {
return self
}
var numeralString = ""
let mappingList: [(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")]
for i in mappingList {
while (integerValue >= i.0) {
integerValue -= i.0
numeralString += i.1
}
}
return numeralString
}
}
感谢Kenneth Bruno提供的一些有关改善代码方面的建议。
for i in mappingList where (integerValue >= i.0) {
,并将所有的mappingList[i]
替换为i
来简化该代码。我还会将其设置为计算属性,这是一个很好的选择。对我来说,这似乎是一个不错的算法! - user887210self
,尽管返回类型应该是String
,而self
是一个Int
。可以通过将第6行的self
替换为self.description
来修复。谢谢你的回答! - undefinedextension Int {
func toRoman() -> String {
let conversionTable: [(intNumber: Int, romanNumber: 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")]
var roman = ""
var remainder = 0
for entry in conversionTable {
let quotient = (self - remainder) / entry.intNumber
remainder += quotient * entry.intNumber
roman += String(repeating: entry.romanNumber, count: quotient)
}
return roman
}
}
String([RomanNumeral](3456)) // MMMCDLVI
import Algorithms
/// A cipher between numbers and strings.
/// - Precondition: `allCases` is sorted.
public protocol NumericCipher: RawRepresentable & CaseIterable
where RawValue: BinaryInteger, AllCases: BidirectionalCollection { }
public extension Array where Element: NumericCipher {
init(_ number: Element.RawValue) {
self = .init(
sequence(
state: (remainder: number, index: Element.allCases.indices.last!)
) { state in
guard let (index, element) = Element.allCases.indexed()
.prefix(through: state.index)
.last(where: { $0.element.rawValue <= state.remainder })
else { return nil }
state.remainder -= element.rawValue
state.index = index
return element
}
)
}
}
public extension String {
init(_ cipher: some Sequence<some NumericCipher>) {
self = cipher.map { "\($0)" }.joined()
}
}
public enum RomanNumeral: Int {
case i = 1
case iv = 4
case v = 5
case x = 10
case xl = 40
case l = 50
case xc = 90
case c = 100
case cd = 400
case d = 500
case cm = 900
case m = 1000
}
extension RomanNumeral: CustomStringConvertible {
public var description: String {
switch self {
case .i: return "I"
case .iv: return "\(Self.i)\(Self.v)"
case .v: return "V"
case .x: return "X"
case .xl: return "\(Self.x)\(Self.l)"
case .l: return "L"
case .xc: return "\(Self.x)\(Self.c)"
case .c: return "C"
case .cd: return "\(Self.c)\(Self.d)"
case .d: return "D"
case .cm: return "\(Self.c)\(Self.m)"
case .m: return "M"
}
}
}
extension RomanNumeral: NumericCipher { }
extension Int {
var romanNumeral: String {
var integerValue = self
var numeralString = ""
let mappingList: [(Int, String)] = [(5000000000000, "O"), (4000000000000, "ZO"), (1000000000000, "Z"),
(900000000000, "QZ"), (500000000000, "Y"), (400000000000, "QY"), (100000000000, "Q"),
(90000000000, "UQ"), (50000000000, "W"), (40000000000, "UW"), (10000000000, "U"),
(9000000000, "BU"), (5000000000, "A"), (4000000000, "BA"), (1000000000, "B"),
(900000000, "GB"), (500000000, "J"), (400000000, "JG"), (100000000, "G"),
(90000000, "TG"), (50000000, "S"), (40000000, "TS"), (10000000, "T"),
(9000000, "RT"), (5000000, "P"), (4000000, "RP"), (1000000, "R"),
(900000, "HR"), (500000, "K"), (400000, "HK"), (100000, "H"),
(90000, "EH"), (50000, "F"), (40000, "EF"), (10000, "E"),
(9000, "ME"), (5000, "N"), (4000, "MN"), (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")]
for i in mappingList {
while (integerValue >= i.0) {
integerValue -= i.0
numeralString += i.1
}
}
return numeralString
}
}
再来一个以确保没有问题:
fileprivate let romanNumerals: [String] = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
fileprivate let arabicNumerals: [Int] = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
extension Int {
var romanRepresentation: String {
guard self > 0 && self < 4000 else {
return "Invalid Number"
}
var control: Int = self
return zip(arabicNumerals, romanNumerals)
.reduce(into: "") { partialResult, ar in
partialResult += String(repeating: ar.1, count: control/ar.0)
control = control % ar.0
}
}
}
extension Int {
func convertToOrdinal() -> String {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .ordinal
guard let ordinalString = numberFormatter.string(from: NSNumber(value: self)) else {
return "\(self)"
}
return ordinalString
}
}