web-dev-qa-db-fra.com

Comment itérer une boucle dans l'ordre inverse rapide?

Lorsque j'utilise la boucle for dans Playground, tout a bien fonctionné, jusqu'à ce que le premier paramètre de boucle soit remplacé par la valeur la plus élevée. (itéré en ordre décroissant)

Est-ce un bug? Quelqu'un d'autre l'avait-il?

for index in 510..509
{
    var a = 10
}

Le compteur qui affiche le nombre d'itérations qui seront des exécutions continue de cocher ...

enter image description here

165
Krishnan

Xcode 6 beta 4 a ajouté deux fonctions pour parcourir les plages avec une étape autre que la suivante: stride(from: to: by:), utilisée avec les plages exclusives, et stride(from: through: by:), utilisée avec les plages incluses.

Pour itérer sur une plage dans l'ordre inverse, ils peuvent être utilisés comme suit:

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

Notez que ni l'une ni l'autre de ces fonctions n'est une fonction membre Range. Ce sont des fonctions globales qui retournent une structure StrideTo ou StrideThrough, définies différemment de la structure Range.

Une version précédente de cette réponse utilisait la fonction membre by() de la structure Range, qui avait été supprimée à la version bêta 4. Si vous voulez voir comment cela fonctionne, consultez l'historique d'édition.

189
Cezar

Appliquez la fonction reverse à la plage pour effectuer une itération inverse:

Pour Swift 1.2 et antérieur:

// Print 10 through 1
for i in reverse(1...10) {
    println(i)
}

Cela fonctionne également avec les gammes semi-ouvertes:

// Print 9 through 1
for i in reverse(1..<10) {
    println(i)
}

Remarque: reverse(1...10) crée un tableau de type [Int]. Par conséquent, bien que cela puisse convenir pour de petites plages, il serait judicieux d'utiliser lazy comme indiqué ci-dessous ou de considérer la réponse acceptée stride si votre plage est grande.


Pour éviter de créer un tableau de grande taille, utilisez lazy avec reverse(). Le test suivant fonctionne efficacement dans une aire de jeu et montre qu'il ne crée pas de tableau avec un billion de Ints!

Test:

var count = 0
for i in lazy(1...1_000_000_000_000).reverse() {
    if ++count > 5 {
        break
    }
    println(i)
}

Pour Swift 2. dans Xcode 7:

for i in (1...10).reverse() {
    print(i)
}

Notez que dans Swift 2.0, (1...1_000_000_000_000).reverse() est de type ReverseRandomAccessCollection<(Range<Int>)>, donc cela fonctionne bien:

var count = 0
for i in (1...1_000_000_000_000).reverse() {
    count += 1
    if count > 5 {
        break
    }
    print(i)
}

Pour Swift 3.reverse() a été renommé en reversed():

for i in (1...10).reversed() {
    print(i) // prints 10 through 1
}
202
vacawama

mis à jour pour Swift 3

La réponse ci-dessous est un résumé des options disponibles. Choisissez celui qui correspond le mieux à vos besoins.

reversed: nombres dans une plage

Transférer

for index in 0..<5 {
    print(index)
}

// 0
// 1
// 2
// 3
// 4

en arrière

for index in (0..<5).reversed() {
    print(index)
}

// 4
// 3
// 2
// 1
// 0

reversed: éléments dans SequenceType

let animals = ["horse", "cow", "camel", "sheep", "goat"]

Transférer

for animal in animals {
    print(animal)
}

// horse
// cow
// camel
// sheep
// goat

en arrière

for animal in animals.reversed() {
    print(animal)
}

// goat
// sheep
// camel
// cow
// horse

reversed: éléments avec un index

Parfois, un index est nécessaire lors d'une itération dans une collection. Pour cela, vous pouvez utiliser enumerate(), qui retourne un tuple. Le premier élément du tuple est l'index et le second élément est l'objet.

let animals = ["horse", "cow", "camel", "sheep", "goat"]

Transférer

for (index, animal) in animals.enumerated() {
    print("\(index), \(animal)")
}

// 0, horse
// 1, cow
// 2, camel
// 3, sheep
// 4, goat

en arrière

for (index, animal) in animals.enumerated().reversed()  {
    print("\(index), \(animal)")
}

// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse

Notez que, comme Ben Lachman l’a noté dans sa réponse , vous voudrez probablement faire .enumerated().reversed() plutôt que .reversed().enumerated() (ce qui augmenterait le nombre d’index).

foulée: nombres

Stride est un moyen d'itérer sans utiliser de plage. Il y a deux formes. Les commentaires à la fin du code indiquent quelle serait la version de la plage (en supposant que la taille de l'incrément est 1).

startIndex.stride(to: endIndex, by: incrementSize)      // startIndex..<endIndex
startIndex.stride(through: endIndex, by: incrementSize) // startIndex...endIndex

Transférer

for index in stride(from: 0, to: 5, by: 1) {
    print(index)
}

// 0
// 1
// 2
// 3
// 4

en arrière

Changer la taille de l'incrément en -1 vous permet de revenir en arrière.

for index in stride(from: 4, through: 0, by: -1) {
    print(index)
}

// 4
// 3
// 2
// 1
// 0

Notez la différence to et through.

stride: éléments de SequenceType

Avancer par incréments de 2

let animals = ["horse", "cow", "camel", "sheep", "goat"]

J'utilise 2 dans cet exemple pour montrer une autre possibilité.

for index in stride(from: 0, to: 5, by: 2) {
    print("\(index), \(animals[index])")
}

// 0, horse
// 2, camel
// 4, goat

en arrière

for index in stride(from: 4, through: 0, by: -1) {
    print("\(index), \(animals[index])")
}

// 4, goat
// 3, sheep 
// 2, camel
// 1, cow  
// 0, horse 

Remarques

85
Suragch

Swift 4 à partir de

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
48
Irfan

Pour Swift 2.0 et versions ultérieures, vous devez appliquer l'inverse sur une collection de plages.

for i in (0 ..< 10).reverse() {
  // process
}

Il a été renommé en .reversed () dans Swift 3.0

27
Andrew Luca

Avec Swift 5, en fonction de vos besoins, vous pouvez choisir l’un des quatre exemples de code suivants: afin de résoudre votre problème. .


#1. Utilisation de la méthode ClosedRangereversed()

ClosedRange a une méthode appelée reversed() . La méthode reversed() a la déclaration suivante:

func reversed() -> ReversedCollection<ClosedRange<Bound>>

Renvoie une vue présentant les éléments de la collection dans l'ordre inverse.

Utilisation:

let reversedCollection = (0 ... 5).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

Vous pouvez également utiliser la méthode Rangereversed() :

let reversedCollection = (0 ..< 6).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

# 2. Utilisation de la fonction sequence(first:next:)

Swift Standard Library fournit une fonction appelée sequence(first:next:) . sequence(first:next:) a la déclaration suivante:

func sequence<T>(first: T, next: @escaping (T) -> T?) -> UnfoldFirstSequence<T>

Retourne une séquence formée à partir de first et d'applications répétées de next.

Utilisation:

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. Utilisation de la fonction stride(from:through:by:)

Swift Standard Library fournit une fonction appelée stride(from:through:by:) . stride(from:through:by:) a la déclaration suivante:

func stride<T>(from start: T, through end: T, by stride: T.Stride) -> StrideThrough<T> where T : Strideable

Renvoie une séquence d'une valeur initiale vers et éventuellement une valeur finale, en progressant de la valeur spécifiée.

Utilisation:

let sequence = stride(from: 5, through: 0, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

Comme alternative, vous pouvez utiliser 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. Utilisation de AnyIteratorinit(_:) initializer

AnyIterator a un initialiseur appelé init(_:) . init(_:) a la déclaration suivante:

init(_ body: @escaping () -> AnyIterator<Element>.Element?)

Crée un itérateur qui enveloppe la fermeture donnée dans sa méthode next().

Utilisation:

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
*/

Si nécessaire, vous pouvez refactoriser le code précédent en créant une méthode d'extension pour Int et en y enveloppant votre itérateur:

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
*/
21
Imanou Petit

Dans Swift 4 et cette dernière

    let count = 50//For example
    for i in (1...count).reversed() {
        print(i)
    }
7
Rohit Sisodia

Swift 4.

for i in stride(from: 5, to: 0, by: -1) {
    print(i) // 5,4,3,2,1
}

Si vous souhaitez inclure la valeur to:

for i in stride(from: 5, through: 0, by: -1) {
    print(i) // 5,4,3,2,1,0
}
4
William Hu

Si l'on veut parcourir un tablea (Array ou plus généralement n'importe quel SequenceType) à l'envers. Vous avez quelques options supplémentaires.

Tout d’abord, vous pouvez reverse() le tableau et le parcourir normalement. Cependant, je préfère utiliser enumerate() la plupart du temps, car il génère un tuple contenant l'objet et son index.

Une chose à noter ici est qu’il est important de les appeler dans le bon ordre:

for (index, element) in array.enumerate().reverse()

donne des indices en ordre décroissant (ce à quoi je m'attends généralement). tandis que:

for (index, element) in array.reverse().enumerate() (ce qui correspond plus étroitement à reverseEnumerator de NSArray)

fait reculer le tableau mais génère des index ascendants.

3
Ben Lachman

comme pour Swift 2.2, Xcode 7.3 (10, juin 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)")
}

Sortie:

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
2
PeiweiChen

Vous pouvez également utiliser la boucle C-Style while. Cela fonctionne très bien dans Swift 3:

var i = 5 
while i > 0 { 
    print(i)
    i -= 1
}
1
Nitin Nain

Vous pouvez utiliser la méthode reverse () pour inverser facilement les valeurs.

var i:Int
for i in 1..10.reversed() {
    print(i)
}

La méthode reverse () inverse les valeurs.

1
SIDHARTH P U
var sum1 = 0
for i in 0...100{
    sum1 += i
}
print (sum1)

for i in (10...100).reverse(){
    sum1 /= i
}
print(sum1)
1
Abo3atef

Pour cela, vous pouvez utiliser la boucle while qui est très facile

var i = 10
while i > 1{
   print(i)
   i = i - 1
}

Mais quand même, si vous voulez utiliser la boucle for, utilisez la méthode reversed()

for i in (1...10).reversed(){
    print(i)
}
0
Abhishek Sharma