web-dev-qa-db-fra.com

Supprimer et ajouter des éléments au tableau dans GO lang

J'ai 2 tableaux déclarés comme: var input []string et var output []string.

Le tableau d'entrée est initialement rempli de quelques ID. Le tableau de sortie est NULL.

Après chaque itération, je veux supprimer un élément aléatoire du tableau d'entrée et l'ajouter au tableau de sortie.

À la fin, tous les éléments du tableau de sortie seront les mêmes que le tableau d'entrée (mais avec un ordre différent (indexation)).

for index := 0; index < len(input); index++ {
    if !visited[index] {
        //do something
    }
}
output[#iteration index] = input[current index]

Lorsque j'essaie de le faire, j'obtiens array out of bounds error.

17
fnaticRC ggwp

Pour le tableau output, vous devez utiliser append ou l'allouer avec une capacité initiale correspondant à la taille de input.

// before the loop
output := make([]string, len(input))

serait ma recommandation car append provoque un tas de réallocations inutiles et vous savez déjà de quelle capacité vous avez besoin car elle est basée sur le input.

L'autre chose serait:

output = append(output, input[index])

Mais comme je l'ai dit, d'après ce que j'ai observé, la capacité initiale augmente de façon exponentielle. Ce sera la base 2 si vous n'avez rien spécifié, ce qui signifie que vous allez faire plusieurs réaffectations inutiles avant d'atteindre la capacité souhaitée.

22
evanmcdonnal

Vous pouvez trouver des astuces utiles sur golang/SliceTricks .

Depuis l'introduction du append intégré, la plupart des fonctionnalités du container/vector package, qui a été supprimé dans Go 1, peut être répliqué à l'aide de append et copy.

Voici les méthodes vectorielles et leurs analogues de manipulation de tranche:

a = append(a, b...)
b = make([]T, len(a))
copy(b, a)
// or
b = append([]T(nil), a...)
a = append(a[:i], a[j:]...)
a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]
a[i] = a[len(a)-1] 
a = a[:len(a)-1]

[~ # ~] note [~ # ~] Si le type de l'élément est un pointeur ou une struct avec les champs de pointeur, qui doivent être récupérés, les implémentations ci-dessus de Cut et Delete ont un potentiel fuite de mémoire problème: certains éléments avec des valeurs sont toujours référencé par la tranche a et ne peut donc pas être collecté. Le code suivant peut résoudre ce problème:

Couper

copy(a[i:], a[j:])
for k, n := len(a)-j+i, len(a); k < n; k++ {
    a[k] = nil // or the zero value of T
}
a = a[:len(a)-j+i]

Supprimer

copy(a[i:], a[i+1:])
a[len(a)-1] = nil // or the zero value of T
a = a[:len(a)-1]

Supprimer sans conserver l'ordre

a[i] = a[len(a)-1]
a[len(a)-1] = nil
a = a[:len(a)-1]
a = append(a[:i], append(make([]T, j), a[i:]...)...)
a = append(a, make([]T, j)...)
a = append(a[:i], append([]T{x}, a[i:]...)...)

[~ # ~] note [~ # ~] Le second append crée une nouvelle tranche avec son propre stockage sous-jacent et copie les éléments dans a[i:] dans cette tranche, et ces éléments sont ensuite recopiés dans la tranche a (par le premier append). La création de la nouvelle tranche (et donc des déchets de mémoire) et de la deuxième copie peut être évitée en utilisant une autre méthode:

Insérer

s = append(s, 0)
copy(s[i+1:], s[i:])
s[i] = x
a = append(a[:i], append(b, a[i:]...)...)
x, a = a[0], a[1:]
x, a = a[len(a)-1], a[:len(a)-1]
a = append(a, x)
a = append([]T{ x }, a...)
x, a := a[0], a[1:]
a = append([]T{x}, a...)

Astuces supplémentaires

Filtrage sans allocation

Cette astuce utilise le fait qu'une tranche partage la même matrice de support et la même capacité que l'original, de sorte que le stockage est réutilisé pour la tranche filtrée. Bien sûr, le contenu original est modifié.

b := a[:0]
for _, x := range a {
    if f(x) {
        b = append(b, x)
    }
}

Inverser

Pour remplacer le contenu d'une tranche par les mêmes éléments mais dans l'ordre inverse:

for i := len(a)/2-1; i >= 0; i-- {
    opp := len(a)-1-i
    a[i], a[opp] = a[opp], a[i]
}

La même chose, sauf avec deux indices:

for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 {
    a[left], a[right] = a[right], a[left]
}

Mélange

Algorithme de Fisher – Yates:

for i := len(a) - 1; i > 0; i-- {
    j := Rand.Intn(i + 1)
    a[i], a[j] = a[j], a[i]
}
5
TonnyL