blob: db8193f34dbe8b4e494fc257511c7ff81c143cc9 [file] [log] [blame] [view]
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11001Since the introduction of the ` append ` built-in, most of the functionality of the ` container/vector ` package, which was removed in Go 1, can be replicated using ` append ` and ` copy `.
2
3Here are the vector methods and their slice-manipulation analogues:
4
Lars Walen35b2d5e2017-03-21 13:54:47 -07005#### AppendVector
Andrew Stone7a268d02015-03-11 13:12:10 -04006```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11007a = append(a, b...)
8```
Dave8f62fba2015-01-08 12:44:59 +11009
Lars Walen35b2d5e2017-03-21 13:54:47 -070010#### Copy
Andrew Stone7a268d02015-03-11 13:12:10 -040011```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110012b = make([]T, len(a))
13copy(b, a)
Jagatheesan Jackddb2ccf2017-05-14 10:32:01 +080014// or
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110015b = append([]T(nil), a...)
Eugene Russkikh3ba038c2018-10-02 22:40:17 +020016// or
17b = append(a[:0:0], a...) // See https://github.com/go101/go101/wiki
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110018```
Dave8f62fba2015-01-08 12:44:59 +110019
Lars Walen35b2d5e2017-03-21 13:54:47 -070020#### Cut
Andrew Stone7a268d02015-03-11 13:12:10 -040021```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110022a = append(a[:i], a[j:]...)
23```
Dave8f62fba2015-01-08 12:44:59 +110024
Lars Walen35b2d5e2017-03-21 13:54:47 -070025#### Delete
Andrew Stone7a268d02015-03-11 13:12:10 -040026```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110027a = append(a[:i], a[i+1:]...)
28// or
29a = a[:i+copy(a[i:], a[i+1:])]
30```
Dave8f62fba2015-01-08 12:44:59 +110031
Maxim Litvinov39410282018-12-31 09:12:50 +020032#### Delete without preserving order
Maxim Litvinov3ddd1702018-12-31 09:11:06 +020033```go
Maxim Litvinov39410282018-12-31 09:12:50 +020034a[i] = a[len(a)-1]
Maxim Litvinov3ddd1702018-12-31 09:11:06 +020035a = a[:len(a)-1]
Maxim Litvinov3ddd1702018-12-31 09:11:06 +020036
Maxim Litvinov39410282018-12-31 09:12:50 +020037```
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110038**NOTE** If the type of the element is a _pointer_ or a struct with pointer fields, which need to be garbage collected, the above implementations of ` Cut ` and ` Delete ` have a potential _memory leak_ problem: some elements with values are still referenced by slice ` a ` and thus can not be collected. The following code can fix this problem:
Dave8f62fba2015-01-08 12:44:59 +110039> **Cut**
Andrew Stone7a268d02015-03-11 13:12:10 -040040```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110041copy(a[i:], a[j:])
Dave Day0d6986a2014-12-10 15:02:18 +110042for k, n := len(a)-j+i, len(a); k < n; k++ {
43 a[k] = nil // or the zero value of T
David Deng2b4bafd2015-04-28 08:01:53 -070044}
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110045a = a[:len(a)-j+i]
46```
Dave8f62fba2015-01-08 12:44:59 +110047
48> **Delete**
Andrew Stone7a268d02015-03-11 13:12:10 -040049```go
Andrew Stone55f404a2015-03-11 13:10:56 -040050copy(a[i:], a[i+1:])
51a[len(a)-1] = nil // or the zero value of T
52a = a[:len(a)-1]
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110053```
Dave8f62fba2015-01-08 12:44:59 +110054
55> **Delete without preserving order**
Andrew Stone7a268d02015-03-11 13:12:10 -040056```go
alandonovanbddf9a52015-07-27 16:15:39 -040057a[i] = a[len(a)-1]
58a[len(a)-1] = nil
59a = a[:len(a)-1]
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110060```
61
Lars Walen35b2d5e2017-03-21 13:54:47 -070062#### Expand
Andrew Stone7a268d02015-03-11 13:12:10 -040063```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110064a = append(a[:i], append(make([]T, j), a[i:]...)...)
65```
Dave8f62fba2015-01-08 12:44:59 +110066
Lars Walen35b2d5e2017-03-21 13:54:47 -070067#### Extend
Andrew Stone7a268d02015-03-11 13:12:10 -040068```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110069a = append(a, make([]T, j)...)
70```
71
Lars Walen35b2d5e2017-03-21 13:54:47 -070072#### Insert
Andrew Stone7a268d02015-03-11 13:12:10 -040073```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110074a = append(a[:i], append([]T{x}, a[i:]...)...)
75```
76**NOTE** The second ` append ` creates a new slice with its own underlying storage and copies elements in ` a[i:] ` to that slice, and these elements are then copied back to slice ` a ` (by the first ` append `). The creation of the new slice (and thus memory garbage) and the second copy can be avoided by using an alternative way:
Dave8f62fba2015-01-08 12:44:59 +110077> **Insert**
Andrew Stone7a268d02015-03-11 13:12:10 -040078```go
Ian Lance Taylorc69144a2018-12-27 14:17:54 -080079s = append(s, 0 /* use the zero value of the element type */)
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110080copy(s[i+1:], s[i:])
81s[i] = x
82```
83
Lars Walen35b2d5e2017-03-21 13:54:47 -070084#### InsertVector
Andrew Stone7a268d02015-03-11 13:12:10 -040085```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110086a = append(a[:i], append(b, a[i:]...)...)
87```
Dave8f62fba2015-01-08 12:44:59 +110088
Maxim Litvinov9ade7aa2018-12-31 09:03:58 +020089#### Push
Andrew Stone7a268d02015-03-11 13:12:10 -040090```go
Maxim Litvinov9ade7aa2018-12-31 09:03:58 +020091a = append(a, x)
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110092```
Dave8f62fba2015-01-08 12:44:59 +110093
Maxim Litvinovf1e07062018-12-31 09:00:22 +020094#### Pop
Helmut Kemper9d79a992017-06-28 10:34:07 -030095```go
Sergey Dobrodey922463f2017-10-10 13:19:56 +030096x, a = a[len(a)-1], a[:len(a)-1]
Helmut Kemper9d79a992017-06-28 10:34:07 -030097```
98
Axel Wagnerd4a15732018-02-04 08:09:46 +010099#### Push Front/Unshift
Andrew Stone7a268d02015-03-11 13:12:10 -0400100```go
Joshua Mervine0ab65812015-03-10 22:28:12 -0700101a = append([]T{x}, a...)
Joshua Mervined37365d2015-03-10 22:25:29 -0700102```
103
Maxim Litvinov9ade7aa2018-12-31 09:03:58 +0200104#### Pop Front/Shift
105```go
106x, a = a[0], a[1:]
107```
108
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100109## Additional Tricks
110### Filtering without allocating
111
112This trick uses the fact that a slice shares the same backing array and capacity as the original, so the storage is reused for the filtered slice. Of course, the original contents are modified.
113
Andrew Stone7a268d02015-03-11 13:12:10 -0400114```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100115b := a[:0]
116for _, x := range a {
Dave Day0d6986a2014-12-10 15:02:18 +1100117 if f(x) {
118 b = append(b, x)
119 }
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100120}
Kamil Kisiel1f350912015-04-20 13:46:59 -0700121```
122
123### Reversing
124
125To replace the contents of a slice with the same elements but in reverse order:
126```go
David Deng2b4bafd2015-04-28 08:01:53 -0700127for i := len(a)/2-1; i >= 0; i-- {
Kamil Kisiel1f350912015-04-20 13:46:59 -0700128 opp := len(a)-1-i
129 a[i], a[opp] = a[opp], a[i]
130}
lemmidb4a3882015-06-26 17:43:13 +0200131```
132The same thing, except with two indices:
133```go
134for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 {
135 a[left], a[right] = a[right], a[left]
136}
Eugene Russkikhf2fde5f2017-11-05 00:53:09 +0100137```
138
139### Shuffling
140
141FisherYates algorithm:
Andrew Stonead72ba52018-05-04 13:34:49 -0700142
143> Since go1.10, this is available at [math/rand.Shuffle](https://godoc.org/math/rand#Shuffle)
144
Eugene Russkikhf2fde5f2017-11-05 00:53:09 +0100145```go
146for i := len(a) - 1; i > 0; i-- {
147 j := rand.Intn(i + 1)
148 a[i], a[j] = a[j], a[i]
149}
Jeremy Loy34857822018-08-13 09:44:20 -0400150```
151
152### Batching with minimal allocation
153
154Useful if you want to do batch processing on large slices.
155
156```go
157actions := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
158batchSize := 3
159var batches [][]int
160
161for batchSize < len(actions) {
162 actions, batches = actions[batchSize:], append(batches, actions[0:batchSize:batchSize])
163}
164batches = append(batches, actions)
165```
166
167Yields the following:
168```go
169[[0 1 2] [3 4 5] [6 7 8] [9]]
Meng Zhuob9434c82018-09-28 14:32:34 +0800170```
171
172### In-place deduplicate (comparable)
173
174```go
175import "sort"
176
177in := []int{3,2,1,4,3,2,1,4,1} // any item can be sorted
178sort.Ints(in)
179j := 0
180for i := 1; i < len(in); i++ {
181 if in[j] == in[i] {
182 continue
183 }
184 j++
Thomas Manginbc97e752018-12-31 17:41:42 +0000185 // preserve the original data
186 // in[i], in[j] = in[j], in[i]
187 // only set what is required
188 in[j] = in[i]
Meng Zhuob9434c82018-09-28 14:32:34 +0800189}
Adam DiCarlod8e8a7f2018-10-18 13:10:48 -0700190result := in[:j+1]
191fmt.Println(result) // [1 2 3 4]
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100192```