it-swarm.com.de

Element in einem Slice löschen

func main() {
    a := []string{"Hello1", "Hello2", "Hello3"}
    fmt.Println(a)
    // [Hello1 Hello2 Hello3]
    a = append(a[:0], a[1:]...)
    fmt.Println(a)
    // [Hello2 Hello3]
}

Wie funktioniert dieser Löschtrick mit der Append-Funktion?

Es scheint, dass es alles vor dem ersten Element (leeres Array) greift

Dann alles nach dem ersten Element anhängen (Position Null)

Was macht der ... (dot dot dot)?

132
Jorge Olivero

Dabei ist a das Segment und i der Index des zu löschenden Elements:

a = append(a[:i], a[i+1:]...)

... ist die Syntax für verschiedene Argumente in Go.

Grundsätzlich werden bei Definieren einer Funktion alle Argumente, die Sie übergeben, in einem Slice dieses Typs abgelegt. Auf diese Weise können Sie so viele Argumente übergeben, wie Sie möchten (z. B. fmt.Println kann beliebig viele Argumente annehmen).

Nun, wenn Aufruf eine Funktion, ... macht das Gegenteil: Es entpackt einen Slice und übergibt sie als separate Argumente an eine variable Funktion.

Also, was macht diese Zeile:

a = append(a[:0], a[1:]...)

ist im Wesentlichen:

a = append(a[:0], a[1], a[2])

Nun fragen Sie sich vielleicht, warum Sie es nicht einfach tun sollten

a = append(a[1:]...)

Nun, die Funktionsdefinition von append ist

func append(slice []Type, elems ...Type) []Type

Das erste Argument muss also ein Slice des richtigen Typs sein, das zweite Argument ist das Variadic. Wir übergeben also ein leeres Slice und packen dann den Rest des Slice aus, um die Argumente auszufüllen.

262
dave

Es gibt zwei Möglichkeiten:

A: Es ist Ihnen wichtig, die Reihenfolge der Arrays beizubehalten:

a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]

B: Es ist dir egal, ob du die Ordnung beibehältst (das ist wahrscheinlich schneller):

a[i] = a[len(a)-1] // Replace it with the last one. CAREFUL only works if you have enough elements.
a = a[:len(a)-1]   // Chop off the last one.

Folgen Sie dem Link, um zu sehen, welche Auswirkungen Speicherverluste haben, wenn Ihr Array Zeiger enthält.

https://github.com/golang/go/wiki/SliceTricks

42
Chris

Anstatt an die Indizes in den Notationen [a:] -, [:b] - und [a:b] - als Elementindizes zu denken, sollten Sie sich diese als Indizes der Lücken um und zwischen den Elementen vorstellen , beginnend mit der Lücke 0 vor dem Element 0.

enter image description here

Wenn man nur die blauen Zahlen betrachtet, ist es viel einfacher zu sehen, was gerade passiert: [0:3] Schließt alles ein, [3:3] Ist leer und [1:2] Würde {"B"} Ergeben. Dann ist [a:] Nur die Kurzversion von [a:len(arrayOrSlice)], [:b] Die Kurzversion von [0:b] Und [:] Die Kurzversion von [0:len(arrayOrSlice)]. Letzteres wird üblicherweise verwendet, um ein Array bei Bedarf in einen Slice zu verwandeln.

9
Zyl

... ist die Syntax für verschiedene Argumente.

Ich denke, es wird vom Complier mit slice ([]Type), Genau wie die Funktion append implementiert:

func append(slice []Type, elems ...Type) []Type

wenn Sie "elems" in "append" verwenden, handelt es sich eigentlich um einen Slice ([] -Typ). "a = append(a[:0], a[1:]...)" bedeutet also "a = append(a[0:0], a[1:])"

a[0:0] Ist ein Slice, das nichts enthält

a[1:] Ist "Hello2 Hello3"

So funktioniert es

5
frank.lin

Ich erhalte einen Indexfehler außerhalb des Bereichs mit der akzeptierten Antwortlösung. Grund: Wenn der Bereich beginnt, wird der Wert nicht einzeln, sondern nach Index iteriert. Wenn Sie ein Segment in Reichweite geändert haben, führt dies zu Problemen.

Alte Antwort:

chars := []string{"a", "a", "b"}

for i, v := range chars {
    fmt.Printf("%+v, %d, %s\n", chars, i, v)
    if v == "a" {
        chars = append(chars[:i], chars[i+1:]...)
    }
}
fmt.Printf("%+v", chars)

Erwartet :

[a a b], 0, a
[a b], 0, a
[b], 0, b
Result: [b]

Tatsächlich:

// Autual
[a a b], 0, a
[a b], 1, b
[a b], 2, b
Result: [a b]

Richtiger Weg (Lösung):

chars := []string{"a", "a", "b"}

for i := 0; i < len(chars); i++ {
    if chars[i] == "a" {
        chars = append(chars[:i], chars[i+1:]...)
        i-- // form the remove item index to start iterate next item
    }
}

fmt.Printf("%+v", chars)

Quelle: https://dinolai.com/notes/golang/golang-delete-slice-item-in-range-problem.html

3
timotew

In Golangs Wiki werden einige Tricks für Slices gezeigt, darunter das Löschen eines Elements aus Slices.

Link: Linkbeschreibung hier eingeben

Beispiel: a ist das Segment, in dem Sie das Element mit der Nummer i löschen möchten.

a = append(a[:i], a[i+1:]...)

OR

a = a[:i+copy(a[i:], a[i+1:])]
3
g10guang

Oder weil Sie versuchen, den Index des Elements zu finden, das ohnehin gelöscht werden soll,

// na = new a, da = a that's to be deleted
var na []string
for _, v := range a {
    if v == da {
        continue
    } else {
        na = append(na, v)
    }
}
a = na

Ok, vergiss 'es. Richtige Antwort für das Thema, aber falsche Antwort für den Fragenkörper.

2
user2312578