Gibt es eine Möglichkeit, in Go in umgekehrter Reihenfolge über ein Slice zu iterieren?

92

Es wäre bequem, etwas sagen zu können wie:

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

Antworten:

134

Nein, es gibt keinen geeigneten Operator, um den vorhandenen Bereich zu erweitern. Sie müssen einen normalen Countdown für die Schleife durchführen:

s := []int{5, 4, 3, 2, 1}
for i := len(s)-1; i >= 0; i-- {
   fmt.Println(s[i])
}
Ulf Holm Nielsen
quelle
Die effektive Go- Seite ist ein Beispiel, aber diese ist tatsächlich ein bisschen schöner und deklariert weniger Variablen.
Kevin Cantwell
3
IMO Go benötigt dringend ein absteigendes Bereichskonstrukt. Wenn wir es nicht haben, entsteht viel zusätzliche Arbeit, wie wir sehen können ... -
Vector
23
Ich würde nicht verzweifelt sagen, es wäre schön zu haben.
Adam Kurkiewicz
45

Sie können auch tun:

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
}

Ausgabe:

1
2
3
4
5

Auch hier: http://play.golang.org/p/l7Z69TV7Vl

zzzz
quelle
12

Variation mit Index

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

Wie wäre es mit Defer verwenden:

s := []int{5, 4, 3, 2, 1}
for i, _ := range s {
   defer fmt.Println(s[i])
}
Matt
quelle
8
Ich habe nur dafür gestimmt, dass es einige neue Erkenntnisse gebracht hat, deferaber ich glaube, dass es ziemlich schwierig ist, dies in einer Schleife für den Rückwärtsgang zu verwenden, und dass es in Bezug auf das Gedächtnis ziemlich ineffektiv sein sollte.
Alexander Trakhimenok
9
Es "funktioniert", aber wenn die Schleife nicht das letzte in der Funktion ist, können unerwartete Ergebnisse erzielt werden. Beispiel.
Daniel
5
Dies wird deferauf eine Weise verwendet, für die es nicht vorgesehen ist. Verwenden Sie dies nicht, da es böse Nebenwirkungen haben kann (Ausführung außerhalb der Reihenfolge). Verwenden Sie einfach die forSchleife in der akzeptierten Antwort. Go ist bestrebt, diese Art von cleveren (nicht) Hacks zu minimieren, da sie dazu neigen, dich später in den Arsch zu beißen.
RickyA
4
Dies ist eine hackige Verwendung von Aufschub und sollte vermieden werden. Wenn dies beispielsweise eine Funktion ist, die jemand in Zukunft erweitern könnte, kann dies unbeabsichtigte Konsequenzen haben.
Amir Keibi
4
Dies war nicht ganz "zweifelhaft" genug, also ging ich voran und fügte Kanäle play.golang.org/p/GodEiv1LlIJ
Xeoncross
4

Man könnte einen Kanal verwenden, um eine Liste in einer Funktion umzukehren, ohne sie zu duplizieren. Es macht den Code in meinem Sinne schöner.

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)
    }
}
user983716
quelle
Das sieht für mich nach einer sauberen und benutzerfreundlichen Lösung aus. Ist es möglich, dies mit dem Typ zu verallgemeinern []interface{}? Weil die Present-Funktion reversenur Strings unterstützt.
Atmocreations
Ersetzen Sie einfach den String durch die Schnittstelle {} und schon kann es losgehen. Ich möchte nur betonen, dass eine Funktion mit Signatur func reverse(lst []interface{}) chan inyterface{} keine [] Zeichenfolge mehr als Eingabe verwendet. Selbst wenn ein String in die Schnittstelle {} umgewandelt werden kann, kann der String [] nicht in die Schnittstelle [] {} umgewandelt werden. Leider ist die vorliegende Umkehrfunktion die Art von Funktion, die viel umgeschrieben werden muss.
user983716
Danke dir. Das ist der hässliche Teil von go, denke ich - was irgendwie unvermeidlich ist. Danke dir!
Atmocreations
Ich würde eher einen Stack als diesen implementieren.
Devrimbaris 7.
0

Wenn ich Elemente aus einem Slice extrahieren und den Bereich umkehren muss, verwende ich so etwas wie diesen 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")
    }
}

Ausgabe:

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}

Spielplatz: https://play.golang.org/p/gx6fJIfb7fo

Vladimir Filin
quelle