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