如果我有整数123并且我想将数字分成数组[1,2,3],这样做的最佳方法是什么?我已经搞砸了很多,我有以下工作:
var number = 123
var digits = Array(String(number)).map{Int(strtoul((String($0)),nil,16))}
我看着它,觉得可能有更好/更简单的方法。如果没有,那么它可能会出现在网络搜索上。任何替代想法?
答案 0 :(得分:7)
更容易处理数字字符串的UTF-8表示 因为十进制数字的UTF-8代码单元可以很容易地转换为 通过减去常数得到相应的整数:
let asciiZero = UInt8(ascii: "0")
let digits = map(String(number).utf8) { Int($0 - asciiZero) }
这也显着加快了。
如果性能是主要目标,那么您应该限制 简单整数运算的方法,不使用字符串 或字符:
var digits : [Int] = []
while number > 0 {
digits.insert(number % 10, atIndex: 0)
number /= 10
}
这是我完整的测试代码,为了您的方便(已编译) 在MacBook Pro上使用Xcode 6.4处于发布模式。)
func digits1(number : Int) -> [Int] {
let digits = Array(String(number)).map{Int(strtoul((String($0)), nil, 16))}
return digits
}
func digits2(number : Int) -> [Int] {
// Use a static property so that the constant is initialized only once.
struct Statics {
static let asciiZero = UInt8(ascii: "0")
}
let digits = map(String(number).utf8) { Int($0 - Statics.asciiZero) }
return digits
}
func digits3(var number : Int) -> [Int] {
var digits : [Int] = []
while number > 0 {
digits.insert(number % 10, atIndex: 0)
number /= 10
}
return digits
}
func measure(converter: (Int)-> [Int]) {
let start = NSDate()
for n in 1 ... 1_000_000 {
let digits = converter(n)
}
let end = NSDate()
println(end.timeIntervalSinceDate(start))
}
measure(digits1) // 10.5 s
measure(digits2) // 1.5 s
measure(digits3) // 0.9 s
Swift 3的更新:
func digits(_ number: Int) -> [Int] {
var number = number
var digits: [Int] = []
while number > 0 {
digits.insert(number % 10, at: 0)
number /= 10
}
return digits
}
print(digits(12345678)) // [1, 2, 3, 4, 5, 6, 7, 8]
这也比附加数字略快 到一个数组并在最后反转它。
答案 1 :(得分:2)
我对 Swift 2 的看法:
var x = 123
var digits = String(x).characters.map { Int(String($0))! } // [1,2,3]
关于角色更明确,所以我觉得它很可读。
答案 2 :(得分:2)
另一个Swift 3替代方案是使用全局sequence(state:next:)
method。
Swift 3.1
let number = 123456
let array = Array(sequence(state: number,
next: { return $0 > 0 ? ($0 % 10, $0 = $0/10).0 : nil }
).reversed())
print(array) // [1, 2, 3, 4, 5, 6]
Swift 3.0
let number = 123456
let array = Array(sequence(state: number,
next: { (num: inout Int) -> Int? in
return num > 0 ? (num % 10, num /= 10).0 : nil
}).reversed())
print(array) // [1, 2, 3, 4, 5, 6]
上述方法假定为非负数,并且还将返回空数组[]
),number
为0
// -123 -> [1, 2, 3]
// 0 -> [0]
// 123 -> [1, 2, 3]
。覆盖所有自然数字如下:
// for some number ...
let number = ...
// Swift 3.1
let array: [Int]
if number == 0 { array = [0] }
else {
array = Array(sequence(state: abs(number),
next: { return $0 > 0 ? ($0 % 10, $0 = $0/10).0 : nil }
).reversed())
}
// Swift 3.0
let array: [Int]
if number == 0 { array = [0] }
else {
array = Array(sequence(state: number,
next: { (num: inout Int) -> Int? in
return num > 0 ? (num % 10, num /= 10).0 : nil
}).reversed())
}
我们可以将上述内容修改为:
()
关于元组返回的一些细节
在上面的单行返回中,我们使用了整齐的“()
- 返回操作内联作为类型(Int, ())
”的元组成员,这是一种方法,我第一次看到@MartinR在他的改进提案中用来更新the following answer。我们使用state
元组的最后一个成员来变异num
属性()
;元组的第一个成员将在执行defer
之前计算 - 在“计算”第二元组成员时返回操作。
我们可以在这个元组方法和使用单个return
和return
语句执行闭包的方法之间进行类比。即,return num > 0 ? (num % 10, num /= 10).0 : nil
声明:
return num > 0 ? { defer { num /= 10 }; return num % 10 }() : nil
也可以通过执行这样的闭包来完成(在此上下文中为“long form”)
sequence(state:next:)
我没有对这两种方法进行基准测试,但我感觉前者在上面next
的上下文中被反复调用会更快。
Swift 3.0 vs 3.1:上面inout
关闭中的匿名参数
由于SR-1976中报告的现已关闭(Swift 3.1及以后版本)错误( inout params 中需要Swift 3中的
这就是我们必须在上面的Swift 3.0解决方案的state
闭包中显式注释next
的类型的原因,而我们可以在{{1}中使用匿名参数用于Swift 3.1解决方案的闭包。
答案 3 :(得分:1)
我不知道你是否对swift很陌生,但让我们清楚一点,你使用map
的方法最适合你想做的事情:)
还有另一种方法我不建议因为对代码结构进行良好的可视化非常重要。
import Foundation
var number2 = 123
var number3 : String = "\(number2)"
var array : [String] = []
var str2 = ""
for i in number3.characters
{
str2.append(i)
var string = NSString(string: "str")
string.doubleValue
array.append(str2)
str2 = ""
}
欢呼声
答案 4 :(得分:0)
我会说如果没有破坏就不要修理它。我可以采用另一种方式,但它不是更短或任何东西:
var number = 123
var digits = map(String(number)) { String($0).toInt() ?? 0 }