Another Swift 3 alternative is making use of the global 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]
The approach above assumes a non-negative number, and will moreover return an empty array ([]
) is case number
is 0
. To cover the full range of natural numbers as follows:
// -123 -> [1, 2, 3]
// 0 -> [0]
// 123 -> [1, 2, 3]
We can modify the above to:
// 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())
}
Some details regarding the tuple return above
In the single line return above, we've made use of the neat "()
-return operation inlined as tuple member of type ()
", a method that I first saw used by @MartinR in his improvement proposal to update the following answer. We use the last member of a (Int, ())
tuple to mutate the state
property num
; the first member of the tuple will be computed prior to the execution of the ()
-return operation in "computing" the 2nd tuple member.
We can draw an analogy between this tuple method and the approach of executing a closure with a single defer
and return
statement. I.e., the return
statement:
return num > 0 ? (num % 10, num /= 10).0 : nil
could also be accomplished by executing such a closure instead ("long form", in this context)
return num > 0 ? { defer { num /= 10 }; return num % 10 }() : nil
I haven't benchmarked these two approaches against each other, but I have a feeling the former will be faster when repeatedly being called as in the context of sequence(state:next:)
above.
Swift 3.0 vs 3.1: anonymous argument in the next
closure above
Due to the now closed (Swift 3.1 and onwards) bug reported in SR-1976 (Closure signature in Swift 3 required for inout params), there's a limitation in Swift's type inference for inout
parameters to closures. See e.g. the following Q&A for details:
This is the reason why we have to explicitly annotate the type of the state
in the next
closure of the Swift 3.0 solution above, whereas we can make use of anonymous arguments in the next
closure for the Swift 3.1 solution.