Existe-t-il un moyen d'itérer sur une tranche en sens inverse dans Go?


95

Ce serait pratique de pouvoir dire quelque chose comme:

for _, element := reverse range mySlice {
        ...
}

Réponses:


139

Non, il n'y a pas d'opérateur pratique à ajouter à la plage en place. Vous devrez faire un compte à rebours normal pour la boucle:

s := []int{5, 4, 3, 2, 1}
for i := len(s)-1; i >= 0; i-- {
   fmt.Println(s[i])
}

La page go efficace est un exemple, mais celle-ci est en fait un peu plus agréable et déclare moins de variables.
Kevin Cantwell

3
IMO Go a désespérément besoin d'une construction de gamme décroissante. Ne pas l'avoir entraîne beaucoup de travail supplémentaire, comme nous pouvons le voir .... -
Vecteur

24
Je ne dirais pas désespérément, ce serait un bon avoir.
Adam Kurkiewicz

46

Vous pouvez également faire:

s := []int{5, 4, 3, 2, 1}
for i := range s {
        fmt.Println(s[len(s)-1-i]) // Suggestion: do `last := len(s)-1` before the loop
}

Production:

1
2
3
4
5

Aussi ici: http://play.golang.org/p/l7Z69TV7Vl


14

Variation avec index

for k := range s {
        k = len(s) - 1 - k
        // now k starts from the end
    }

6

Que diriez-vous d'utiliser différer:

s := []int{5, 4, 3, 2, 1}
for i, _ := range s {
   defer fmt.Println(s[i])
}

8
J'ai voté juste pour le fait que cela ait apporté de nouvelles connaissances, defermais je pense que l'utiliser dans une boucle pour inverser est assez délicat et devrait être assez inefficace en termes de mémoire.
Alexander Trakhimenok

10
Cela "fonctionne", mais si la boucle n'est pas la dernière chose de la fonction, vous pouvez obtenir des résultats inattendus. Exemple.
Daniel

5
Ceci est utilisé deferd'une manière pour laquelle il n'est pas prévu. Ne l'utilisez pas car cela peut avoir des effets secondaires désagréables (exécution dans le désordre). Utilisez simplement la forboucle dans la réponse acceptée. Go vise à minimiser ce genre de hacks intelligents (pas) car ils ont tendance à vous mordre le cul plus tard.
RickyA

4
Il s'agit d'une utilisation malveillante du report et doit être évitée. S'il s'agit, par exemple, d'une fonction que quelqu'un pourrait étendre à l'avenir, cela peut avoir des conséquences involontaires.
Amir Keibi

4
Ce n'était pas assez `` douteux '', alors je suis allé de l'avant et j'ai ajouté des chaînes play.golang.org/p/GodEiv1LlIJ
Xeoncross

4

On pourrait utiliser un canal pour inverser une liste dans une fonction sans la dupliquer. Cela rend le code plus agréable à mon sens.

package main

import (
    "fmt"
)

func reverse(lst []string) chan string {
    ret := make(chan string)
    go func() {
        for i, _ := range lst {
            ret <- lst[len(lst)-1-i]
        }
        close(ret)
    }()
    return ret
}

func main() {
    elms := []string{"a", "b", "c", "d"}
    for e := range reverse(elms) {
        fmt.Println(e)
    }
}

Cela me semble être une solution propre et agréable à utiliser. Est-il possible de généraliser cela en utilisant le type []interface{}? Parce que la fonction actuelle reversene prend en charge que les chaînes.
Atmocreations

Bien sûr, remplacez simplement string par interface {} et vous êtes prêt à aller. Je veux juste souligner qu'une fonction avec signature func reverse(lst []interface{}) chan inyterface{} ne prendra plus une chaîne [] comme entrée. Même si la chaîne peut être castée dans l'interface {}, la chaîne [] ne peut pas être castée dans [] interface {}. Malheureusement, la fonction inverse actuelle est le genre de fonction qui a beaucoup besoin d'être réécrite.
user983716

Je vous remercie. C'est la partie laide du go je pense - qui est en quelque sorte inévitable. Je vous remercie!
Atmocreations

Je voudrais implémenter une pile plutôt que cela.
的 devrimbaris

0

Lorsque j'ai besoin d'extraire des éléments d'une tranche et d'une plage inversée, j'utilise quelque chose comme ce code:

// reverse range
// Go Playground: https://play.golang.org/p/gx6fJIfb7fo
package main

import (
    "fmt"
)

type Elem struct {
    Id   int64
    Name string
}

type Elems []Elem

func main() {
    mySlice := Elems{{Id: 0, Name: "Alice"}, {Id: 1, Name: "Bob"}, {Id: 2, Name: "Carol"}}
    for i, element := range mySlice {
        fmt.Printf("Normal  range: [%v] %+v\n", i, element)
    }

    //mySlice = Elems{}
    //mySlice = Elems{{Id: 0, Name: "Alice"}}
    if last := len(mySlice) - 1; last >= 0 {
        for i, element := last, mySlice[0]; i >= 0; i-- {
            element = mySlice[i]
            fmt.Printf("Reverse range: [%v] %+v\n", i, element)
        }
    } else {
        fmt.Println("mySlice empty")
    }
}

Production:

Normal  range: [0] {Id:0 Name:Alice}
Normal  range: [1] {Id:1 Name:Bob}
Normal  range: [2] {Id:2 Name:Carol}
Reverse range: [2] {Id:2 Name:Carol}
Reverse range: [1] {Id:1 Name:Bob}
Reverse range: [0] {Id:0 Name:Alice}

Aire de jeu: https://play.golang.org/p/gx6fJIfb7fo

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.