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 {
        ...
}

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])
}

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


12

Variation mit Index

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

5

Wie wäre es mit Defer verwenden:

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

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)
    }
}

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.