问题
When I use the for loop in Playground, everything worked fine, until I changed the first parameter of for loop to be the highest value. (iterated in descending order)
Is this a bug? Did any one else have it?
for index in 510..509
{
var a = 10
}
The counter that displays the number of iterations that will be executions keeps ticking...
回答1:
Xcode 6 beta 4 added two functions to iterate on ranges with a step other than one:
stride(from: to: by:)
, which is used with exclusive ranges and stride(from: through: by:)
, which is used with inclusive ranges.
To iterate on a range in reverse order, they can be used as below:
for index in stride(from: 5, to: 1, by: -1) {
print(index)
}
//prints 5, 4, 3, 2
for index in stride(from: 5, through: 1, by: -1) {
print(index)
}
//prints 5, 4, 3, 2, 1
Note that neither of those is a Range
member function. They are global functions that return either a StrideTo
or a StrideThrough
struct, which are defined differently from the Range
struct.
A previous version of this answer used the by()
member function of the Range
struct, which was removed in beta 4. If you want to see how that worked, check the edit history.
回答2:
Apply the reverse function to the range to iterate backwards:
For Swift 1.2 and earlier:
// Print 10 through 1
for i in reverse(1...10) {
println(i)
}
It also works with half-open ranges:
// Print 9 through 1
for i in reverse(1..<10) {
println(i)
}
Note: reverse(1...10)
creates an array of type [Int]
, so while this might be fine for small ranges, it would be wise to use lazy
as shown below or consider the accepted stride
answer if your range is large.
To avoid creating a large array, use lazy
along with reverse()
. The following test runs efficiently in a Playground showing it is not creating an array with one trillion Int
s!
Test:
var count = 0
for i in lazy(1...1_000_000_000_000).reverse() {
if ++count > 5 {
break
}
println(i)
}
For Swift 2.0 in Xcode 7:
for i in (1...10).reverse() {
print(i)
}
Note that in Swift 2.0, (1...1_000_000_000_000).reverse()
is of type ReverseRandomAccessCollection<(Range<Int>)>
, so this works fine:
var count = 0
for i in (1...1_000_000_000_000).reverse() {
count += 1
if count > 5 {
break
}
print(i)
}
For Swift 3.0 reverse()
has been renamed to reversed()
:
for i in (1...10).reversed() {
print(i) // prints 10 through 1
}
回答3:
Updated for Swift 3
The answer below is a summary of the available options. Choose the one that best fits your needs.
reversed
: numbers in a range
Forward
for index in 0..<5 {
print(index)
}
// 0
// 1
// 2
// 3
// 4
Backward
for index in (0..<5).reversed() {
print(index)
}
// 4
// 3
// 2
// 1
// 0
reversed
: elements in SequenceType
let animals = ["horse", "cow", "camel", "sheep", "goat"]
Forward
for animal in animals {
print(animal)
}
// horse
// cow
// camel
// sheep
// goat
Backward
for animal in animals.reversed() {
print(animal)
}
// goat
// sheep
// camel
// cow
// horse
reversed
: elements with an index
Sometimes an index is needed when iterating through a collection. For that you can use enumerate()
, which returns a tuple. The first element of the tuple is the index and the second element is the object.
let animals = ["horse", "cow", "camel", "sheep", "goat"]
Forward
for (index, animal) in animals.enumerated() {
print("\(index), \(animal)")
}
// 0, horse
// 1, cow
// 2, camel
// 3, sheep
// 4, goat
Backward
for (index, animal) in animals.enumerated().reversed() {
print("\(index), \(animal)")
}
// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse
Note that as Ben Lachman noted in his answer, you probably want to do .enumerated().reversed()
rather than .reversed().enumerated()
(which would make the index numbers increase).
stride: numbers
Stride is way to iterate without using a range. There are two forms. The comments at the end of the code show what the range version would be (assuming the increment size is 1).
startIndex.stride(to: endIndex, by: incrementSize) // startIndex..<endIndex
startIndex.stride(through: endIndex, by: incrementSize) // startIndex...endIndex
Forward
for index in stride(from: 0, to: 5, by: 1) {
print(index)
}
// 0
// 1
// 2
// 3
// 4
Backward
Changing the increment size to -1
allows you to go backward.
for index in stride(from: 4, through: 0, by: -1) {
print(index)
}
// 4
// 3
// 2
// 1
// 0
Note the to
and through
difference.
stride: elements of SequenceType
Forward by increments of 2
let animals = ["horse", "cow", "camel", "sheep", "goat"]
I'm using 2
in this example just to show another possibility.
for index in stride(from: 0, to: 5, by: 2) {
print("\(index), \(animals[index])")
}
// 0, horse
// 2, camel
// 4, goat
Backward
for index in stride(from: 4, through: 0, by: -1) {
print("\(index), \(animals[index])")
}
// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse
Notes
@matt has an interesting solution where he defines his own reverse operator and calls it
>>>
. It doesn't take much code to define and is used like this:for index in 5>>>0 { print(index) } // 4 // 3 // 2 // 1 // 0
Check out On C-Style For Loops Removed from Swift 3
回答4:
Swift 4 onwards
for i in stride(from: 5, to: 0, by: -1) {
print(i)
}
//prints 5, 4, 3, 2, 1
for i in stride(from: 5, through: 0, by: -1) {
print(i)
}
//prints 5, 4, 3, 2, 1, 0
回答5:
For Swift 2.0 and above you should apply reverse on a range collection
for i in (0 ..< 10).reverse() {
// process
}
It has been renamed to .reversed() in Swift 3.0
回答6:
With Swift 5, according to your needs, you may choose one of the four following Playground code examples in order to solve your problem.
#1. Using ClosedRange
reversed()
method
ClosedRange
has a method called reversed(). reversed()
method has the following declaration:
func reversed() -> ReversedCollection<ClosedRange<Bound>>
Returns a view presenting the elements of the collection in reverse order.
Usage:
let reversedCollection = (0 ... 5).reversed()
for index in reversedCollection {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
As an alternative, you can use Range
reversed() method:
let reversedCollection = (0 ..< 6).reversed()
for index in reversedCollection {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
#2. Using sequence(first:next:)
function
Swift Standard Library provides a function called sequence(first:next:). sequence(first:next:)
has the following declaration:
func sequence<T>(first: T, next: @escaping (T) -> T?) -> UnfoldFirstSequence<T>
Returns a sequence formed from
first
and repeated lazy applications ofnext
.
Usage:
let unfoldSequence = sequence(first: 5, next: {
$0 > 0 ? $0 - 1 : nil
})
for index in unfoldSequence {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
#3. Using stride(from:through:by:)
function
Swift Standard Library provides a function called stride(from:through:by:). stride(from:through:by:)
has the following declaration:
func stride<T>(from start: T, through end: T, by stride: T.Stride) -> StrideThrough<T> where T : Strideable
Returns a sequence from a starting value toward, and possibly including, an end value, stepping by the specified amount.
Usage:
let sequence = stride(from: 5, through: 0, by: -1)
for index in sequence {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
As an alternative, you can use stride(from:to:by:):
let sequence = stride(from: 5, to: -1, by: -1)
for index in sequence {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
#4. Using AnyIterator
init(_:)
initializer
AnyIterator
has an initializer called init(_:). init(_:)
has the following declaration:
init(_ body: @escaping () -> AnyIterator<Element>.Element?)
Creates an iterator that wraps the given closure in its
next()
method.
Usage:
var index = 5
guard index >= 0 else { fatalError("index must be positive or equal to zero") }
let iterator = AnyIterator({ () -> Int? in
defer { index = index - 1 }
return index >= 0 ? index : nil
})
for index in iterator {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
If needed, you can refactor the previous code by creating an extension method for Int
and wrapping your iterator in it:
extension Int {
func iterateDownTo(_ endIndex: Int) -> AnyIterator<Int> {
var index = self
guard index >= endIndex else { fatalError("self must be greater than or equal to endIndex") }
let iterator = AnyIterator { () -> Int? in
defer { index = index - 1 }
return index >= endIndex ? index : nil
}
return iterator
}
}
let iterator = 5.iterateDownTo(0)
for index in iterator {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
回答7:
In Swift 4 and latter
let count = 50//For example
for i in (1...count).reversed() {
print(i)
}
回答8:
Swift 4.0
for i in stride(from: 5, to: 0, by: -1) {
print(i) // 5,4,3,2,1
}
If you want to include the to
value:
for i in stride(from: 5, through: 0, by: -1) {
print(i) // 5,4,3,2,1,0
}
回答9:
If one is wanting to iterate through an array (Array
or more generally any SequenceType
) in reverse. You have a few additional options.
First you can reverse()
the array and loop through it as normal. However I prefer to use enumerate()
much of the time since it outputs a tuple containing the object and it's index.
The one thing to note here is that it is important to call these in the right order:
for (index, element) in array.enumerate().reverse()
yields indexes in descending order (which is what I generally expect). whereas:
for (index, element) in array.reverse().enumerate()
(which is a closer match to NSArray's reverseEnumerator
)
walks the array backward but outputs ascending indexes.
回答10:
as for Swift 2.2 , Xcode 7.3 (10,June,2016) :
for (index,number) in (0...10).enumerate() {
print("index \(index) , number \(number)")
}
for (index,number) in (0...10).reverse().enumerate() {
print("index \(index) , number \(number)")
}
Output :
index 0 , number 0
index 1 , number 1
index 2 , number 2
index 3 , number 3
index 4 , number 4
index 5 , number 5
index 6 , number 6
index 7 , number 7
index 8 , number 8
index 9 , number 9
index 10 , number 10
index 0 , number 10
index 1 , number 9
index 2 , number 8
index 3 , number 7
index 4 , number 6
index 5 , number 5
index 6 , number 4
index 7 , number 3
index 8 , number 2
index 9 , number 1
index 10 , number 0
回答11:
You can use reversed() method for easily reverse values.
var i:Int
for i in 1..10.reversed() {
print(i)
}
The reversed() method reverse the values.
回答12:
var sum1 = 0
for i in 0...100{
sum1 += i
}
print (sum1)
for i in (10...100).reverse(){
sum1 /= i
}
print(sum1)
回答13:
You can consider using the C-Style while
loop instead. This works just fine in Swift 3:
var i = 5
while i > 0 {
print(i)
i -= 1
}
回答14:
For this, you can able to use while
loop which is very easy
var i = 10
while i > 1{
print(i)
i = i - 1
}
But still, if you want to use for loop then use reversed()
method
for i in (1...10).reversed(){
print(i)
}
回答15:
You can simply do this if you have an array
func reverseArray(a: [Int]) -> [Int] {
var reverseArr = [Int]()
for i in stride(from: a.count-1, to: -1, by: -1){
reverseArr.append(a[i])
}
return reverseArr
}
来源:https://stackoverflow.com/questions/24508592/how-to-iterate-for-loop-in-reverse-order-in-swift