Elimina l'elemento in una sezione


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

Come funziona questo trucco di eliminazione con la funzione append?

Sembrerebbe che afferri tutto prima del primo elemento (array vuoto)

Quindi aggiungere tutto dopo il primo elemento (posizione zero)

Cosa fa il ... (punto punto punto)?



3
Perché non dare un'occhiata alle specifiche della lingua? ...è spiegato lì in dettaglio?
Volker,

9
Da un lato, assolutamente vero ( golang.org/ref/spec , tutti); dall'altro, c'è abbastanza familiarità con questi idiomi per la migrazione dei pitonisti, ecc. che non mi dispiace avere una spiegazione là fuori che gli altri possano trovare.
due

Risposte:


276

Dov'è ala sezione ed iè l'indice dell'elemento che si desidera eliminare:

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

... è la sintassi per argomenti variadici in Go.

Fondamentalmente, quando si definisce una funzione, inserisce tutti gli argomenti passati in una porzione di quel tipo. In questo modo, puoi passare tutti gli argomenti che desideri (ad esempio, fmt.Printlnpuoi prendere tutti gli argomenti che desideri).

Ora, quando si chiama una funzione, ...fa il contrario: decomprime una sezione e le passa come argomenti separati a una funzione variadica.

Quindi cosa fa questa linea:

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

è essenzialmente:

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

Ora, ti starai chiedendo, perché non farlo

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

Bene, la definizione della funzione di appendè

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

Quindi il primo argomento deve essere una porzione del tipo corretto, il secondo argomento è la variabile, quindi passiamo in una sezione vuota e quindi scompattiamo il resto della sezione per riempire gli argomenti.


35
Non esci dall'eccezione del range se sono l'ultimo elemento della sezione? a = append(a[:i], a[i+1:]...)
themihai,

5
@DaveC Ottengo quell'errore quando lavoro con i miei slice nel mio progetto: /
Tyguy7

3
@ Tyguy7 dalla specifica: "Per array o stringhe, gli indici sono nell'intervallo se 0 <= basso <= alto <= len (a), altrimenti sono fuori intervallo." Forse nel tuo caso alto <basso; in tal caso otterrai l'errore. ( golang.org/ref/spec#Slice_expressions )
mlg

2
Come è la performance di questo? Spero seriamente che non stia creando una fetta completamente nuova sotto il cofano ..
stia

7
@ Tyguy7 Penso che tu abbia provato a eliminare elementi di slice all'interno di un loop. Quindi devi stare attento con gli indici.
Nikolay Bystritskiy

42

Esistono due opzioni:

A: Ti interessa mantenere l'ordine dell'array:

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

B: Non ti interessa mantenere l'ordine (questo è probabilmente più veloce):

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.

Vedere il collegamento per vedere le implicazioni sulle perdite di memoria se l'array è di puntatori.

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


Questo è interessante, ma non risponde davvero alla domanda
Bryan,

Questo è carino, ma sarebbe stato meglio se fosse in grado di eliminare l'unico elemento dell'array
Naguib Ihab,

2
Solo un avvertimento, tentato di usare il primo da b (sostituisci con l'ultimo elemento) non funziona ovviamente se stai tentando di rimuovere l'ultimo elemento nella fetta lol
Sirens,

13

Piuttosto che pensare agli indici nelle annotazioni [a:]-, [:b]- e [a:b]-come a indici di elementi, pensali come gli indici delle lacune intorno e tra gli elementi, iniziando con il gap indicizzato 0prima dell'elemento indicizzato come 0.

inserisci qui la descrizione dell'immagine

Guardando solo i numeri blu, è molto più facile vedere cosa sta succedendo: [0:3]racchiude tutto, [3:3]è vuoto e [1:2]cederebbe {"B"}. Quindi [a:]è solo la versione breve di [a:len(arrayOrSlice)], [:b]la versione corta di [0:b]e [:]la versione corta di [0:len(arrayOrSlice)]. Quest'ultimo è comunemente usato per trasformare un array in una sezione quando necessario.


1
Questo aiuta a spiegare perché la risposta è "no" al commento di themihai sulla risposta di Dave , riferendosi a [i + 1:] anche quando si fa riferimento al suo elemento: play.golang.org/p/E0lQ3jPcjX5
Nick P

5

... è sintassi per argomenti variadici.

Penso che sia implementato dal complier usando slice ( []Type), proprio come la funzione append:

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

quando usi "elems" in "append", in realtà si tratta di una sezione ([] tipo). Quindi " a = append(a[:0], a[1:]...)" significa " a = append(a[0:0], a[1:])"

a[0:0] è una fetta che non ha nulla

a[1:] è "Hello2 Hello3"

È così che funziona


2
a[0:0]non è nilche una sezione con lunghezza 0. a[0:0]sarà solo essere nilse aè nil.
Icza,

5

Ricevo un indice di errore fuori intervallo con la soluzione di risposta accettata. Motivo: quando l'intervallo inizia, non è iterare il valore uno per uno, è iterare per indice. Se hai modificato una sezione mentre è nell'intervallo, causerà qualche problema.

Vecchia risposta:

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)

Previsto :

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

Effettivo:

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

Modo corretto (soluzione):

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)

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


3

Nella wiki di Golang mostra alcuni trucchi per lo slice, incluso eliminare un elemento dallo slice.

Link: inserisci qui la descrizione del link

Ad esempio a è la sezione in cui si desidera eliminare l'elemento numero i.

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

O

a = a[:i+copy(a[i:], a[i+1:])]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.