Supprimer un élément dans une tranche


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

Comment fonctionne cette astuce de suppression avec la fonction d'ajout?

Il semblerait qu'il saisisse tout avant le premier élément (tableau vide)

Puis tout ajouter après le premier élément (position zéro)

Que fait le ... (point point point)?



3
Pourquoi ne pas jeter un œil à la spécification du langage? ...y est expliqué en détail?
Volker

9
D'une part, absolument vrai ( golang.org/ref/spec , tout le monde); de l'autre, ces idiomes ne sont pas assez familiers pour faire migrer les pythonistes, etc.
twotwotwo

Réponses:


276

aest la tranche et iest l'index de l'élément que vous souhaitez supprimer:

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

... est la syntaxe des arguments variadiques dans Go.

Fondamentalement, lors de la définition d' une fonction, il place tous les arguments que vous passez dans une tranche de ce type. En faisant cela, vous pouvez passer autant d'arguments que vous le souhaitez (par exemple, vous fmt.Printlnpouvez prendre autant d'arguments que vous le souhaitez).

Maintenant, lors de l' appel d' une fonction, ...fait le contraire: il décompresse une tranche et les transmet comme arguments séparés à une fonction variadique.

Alors ce que fait cette ligne:

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

est essentiellement:

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

Maintenant, vous vous demandez peut-être pourquoi ne pas simplement faire

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

Eh bien, la définition de la fonction appendest

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

Le premier argument doit donc être une tranche du type correct, le second argument est la variable, donc nous passons dans une tranche vide, puis décompressons le reste de la tranche pour remplir les arguments.


35
Ne sortez-vous pas d'exception hors de portée si i est le dernier élément de la tranche? a = append(a[:i], a[i+1:]...)
themihai

5
@DaveC J'obtiens cette erreur lorsque je travaille avec mes tranches dans mon projet: /
Tyguy7

3
@ Tyguy7 de la spécification: "Pour les tableaux ou les chaînes, les indices sont dans la plage si 0 <= faible <= élevé <= len (a), sinon ils sont hors plage." Peut-être dans votre cas haut <bas; dans ce cas, vous obtiendrez l'erreur. ( golang.org/ref/spec#Slice_expressions )
mlg

2
Quelle est la performance de cela? J'espère sérieusement que cela ne crée pas une tranche entièrement nouvelle sous le capot ..
joonas.fi

7
@ Tyguy7 Je pense que vous avez essayé de supprimer des éléments de tranche dans une boucle. Il faut donc être prudent avec les index.
Nikolay Bystritskiy

42

Il existe deux options:

R: Vous vous souciez de conserver l'ordre des tableaux:

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

B: Vous ne vous souciez pas de conserver l'ordre (c'est probablement plus rapide):

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.

Consultez le lien pour voir les implications des fuites de mémoire si votre tableau est composé de pointeurs.

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


Ceci est intéressant, mais ne répond pas vraiment à la question
Bryan

C'est bien, mais cela aurait été mieux s'il pouvait supprimer le seul élément du tableau
Naguib Ihab

2
Juste un avertissement, tenté d'utiliser le premier de b (remplacer par le dernier élément) ne fonctionne évidemment pas si vous essayez de supprimer le dernier élément de la tranche lol
Sirens

13

Plutôt que de considérer les indices dans les notations [a:]-, [:b]- et - [a:b]comme des indices d'élément, considérez-les comme les indices des écarts autour et entre les éléments, en commençant par l'écart indexé 0avant l'élément indexé comme 0.

entrez la description de l'image ici

En regardant uniquement les nombres bleus, il est beaucoup plus facile de voir ce qui se passe: [0:3]renferme tout, [3:3]est vide et [1:2]céderait {"B"}. Ensuite, il [a:]n'y a que la version courte de [a:len(arrayOrSlice)], [:b]la version courte de [0:b]et [:]la version courte de [0:len(arrayOrSlice)]. Ce dernier est couramment utilisé pour transformer un tableau en une tranche en cas de besoin.


1
Cela aide à expliquer pourquoi la réponse est «non» au commentaire de themihai sur la réponse de dave , faisant référence à [i + 1:] même en se référant au ième élément: play.golang.org/p/E0lQ3jPcjX5
Nick P

5

... est la syntaxe des arguments variadiques.

Je pense qu'il est implémenté par le complicateur en utilisant slice ( []Type), tout comme la fonction append:

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

lorsque vous utilisez "elems" dans "append", il s'agit en fait d'une tranche (type []). Donc " a = append(a[:0], a[1:]...)" signifie " a = append(a[0:0], a[1:])"

a[0:0] est une tranche qui n'a rien

a[1:] est "Hello2 Hello3"

Voilà comment cela fonctionne


2
a[0:0]n'est pas nilqu'une tranche de 0 longueur. a[0:0]sera seulement être nilsi aest nil.
icza

5

J'obtiens une erreur d'index hors limites avec la solution de réponse acceptée. Raison: lorsque la plage commence, ce n'est pas une itération de la valeur une par une, elle est itérée par index. Si vous modifiez une tranche alors qu'elle est à portée, cela induira un problème.

Ancienne réponse:

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)

Attendu:

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

Réel:

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

Bonne manière (solution):

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)

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


3

Dans le wiki de Golang, il montre quelques astuces pour la tranche, y compris la suppression d'un élément de la tranche.

Lien: entrez la description du lien ici

Par exemple, a est la tranche dont vous souhaitez supprimer l'élément numéro i.

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

OU

a = a[:i+copy(a[i:], a[i+1:])]
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.