Go'da bir dilimi tersine yinelemenin bir yolu var mı?


98

Şöyle bir şey söyleyebilmek uygun olacaktır:

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

Yanıtlar:


146

Yerinde bir aralığa eklemek için bunun için uygun bir operatör yoktur. Geri sayım için normal bir for döngüsü yapmanız gerekecek:

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

Etkili go sayfa bir örnek, ama bu aslında biraz daha güzel ve daha az değişken bildirir.
Kevin Cantwell

3
IMO Go'nun azalan bir aralık yapısına umutsuzca ihtiyacı var. Gördüğümüz gibi, buna sahip olmamak çok fazla ekstra çalışmaya neden olur .... -
Vektör

24
Umutsuzca demezdim, güzel bir sahip olur.
Adam Kurkiewicz

47

Ayrıca şunları da yapabilirsiniz:

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
}

Çıktı:

1
2
3
4
5

Ayrıca burada: http://play.golang.org/p/l7Z69TV7Vl


15

Endeksli varyasyon

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

6

Ertelemeye ne dersiniz:

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

9
Sadece bazı yeni bilgiler getirdiği için yukarı oy verdim, deferancak bunu bir döngü içinde tersine çevirmek için kullanmanın oldukça zor olduğuna ve hafıza açısından oldukça etkisiz olması gerektiğine inanıyorum.
Alexander Trakhimenok

11
"Çalışır", ancak döngü işlevdeki son şey değilse, beklenmedik sonuçlar alabilirsiniz. Misal.
Daniel

6
Bu, deferamaçlanmayan bir şekilde kullanılıyor . Kötü yan etkileri olabileceğinden bunu kullanmayın (sıra dışı uygulama). Sadece forkabul edilen cevapta döngüyü kullanın . Go, daha sonra sizi kıçınıza sokma eğiliminde olduklarından , bu tür zekice (değil) saldırıları en aza indirmeyi amaçlamaktadır .
RickyA

6
Bu, ertelemenin karmaşık bir kullanımıdır ve bundan kaçınılmalıdır. Örneğin bu, birisinin gelecekte genişletebileceği bir işlevse, istenmeyen sonuçları olabilir.
Amir Keibi

6
Devam ettim ve böylece bu, oldukça 'şüpheli' yeterli değildi eklenen kanallar play.golang.org/p/GodEiv1LlIJ
Xeoncross

4

Bir işlevdeki bir listeyi çoğaltmadan ters çevirmek için bir kanal kullanılabilir. Bence kodu daha güzel yapıyor.

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

Bu bana temiz ve kullanımı güzel bir çözüm gibi görünüyor. Bunu türü kullanarak genellemek mümkün mü []interface{}? Çünkü şimdiki reverseişlevi yalnızca dizeleri destekler.
Atmocreations

Elbette, dizeyi arayüzle {} değiştirin ve hazırsınız. İmzalı bir işlevin func reverse(lst []interface{}) chan inyterface{} artık girdi olarak bir [] dizesi almayacağını vurgulamak istiyorum . {} Arayüzünde dizge dönüştürülebilir olsa bile, [] dizesi [] arabirim {} içinde dönüştürülemez. Ne yazık ki, şimdiki ters işlev, çok fazla yeniden yazılması gereken işlev türüdür.
user983716

Teşekkür ederim. Bence gitmenin çirkin kısmı bu - ki bu bir şekilde kaçınılmaz. Teşekkür ederim!
Atmocreations

Bunun yerine bir yığın uygulardım.
ᐅ devrimbaris

0

Bir dilimden ve ters aralıktan öğeler çıkarmam gerektiğinde, şu kod gibi bir şey kullanıyorum:

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

Çıktı:

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}

Oyun alanı: https://play.golang.org/p/gx6fJIfb7fo

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.