复制
使用内置的 copy
函数
b = make([]T, len(a)) // 一次将内存申请到位
copy(b, a)
插入元素
开头插入
var a = []int{1, 2, 3}
a = append([]int{0}, a...) // 在开头添加一个元素
需要注意的是,在切片开头插入元素,一般都会导致内存的重新分配和已有元素的全部复制一次。
中间插入
var a = []int{1, 2, 3}
a = append(a, 0) // 扩充空间
copy(a[i+1:], a[i]) // a[i:] 向后移动一个元素
a[i] = 10 // 设置新的元素
删除元素
开头或者结尾删除:
var a = []int{1, 2, 3}
a = a[1:] // 开头删除
a = a[:len(a)-1] // 结尾删除
中间删除:
var a = []int{1, 2, 3, 4, 5, 6}
a = a[:2 + copy(a[2:], a[2+1:])] // 删除第2个元素, 公式: a[: i + copy(a[i:], a[i+1:])]
fmt.Println("a: ", a) // a: [1 2 4 5 6]
var b = []int{1, 2, 3, 4, 5, 6}
b = b[:1 + copy(b[1:], b[1+3:])] // 删除[1, 1+3)元素, 公式: b[: i + copy(b[i:], b[i+N:])]
fmt.Println("b: ", b) // a: [1 2 4 5 6]
过滤
n := 0
for _, x := range a {
if keep(x) {
a[n] = x // 保留该元素
n++
}
}
a = a[:n] // 截取切片中需保留的元素
弹出元素
将切片a的最后一个元素弹出。
x, a = a[len(a)-1], a[:len(a)-1]
弹出切片a的第一个元素。
x, a = a[0], a[1:]
翻转
双指针
for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 {
a[left], a[right] = a[right], a[left]
}
打乱顺序
Fisher–Yates算法:
for i := len(a) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
a[i], a[j] = a[j], a[i]
}
从go1.10开始,可以使用math/rand.Shuffle。
rand.Shuffle(len(a), func(i, j int) {
a[i], a[j] = a[j], a[i]
})
分批处理
actions := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
batchSize := 5
batches := make([][]int, 0, (len(actions) + batchSize - 1) / batchSize)
for batchSize < len(actions) {
actions, batches = actions[batchSize:], append(batches, actions[0:batchSize:batchSize])
}
batches = append(batches, actions)
fmt.Println(batches) // 输出:[[0 1 2 3 4] [5 6 7 8 9]]
就地删除重复元素
滑动窗口
func main() {
a := []int{1, 2, 3, 4, 5}
res := slidingWindow(2, a)
fmt.Println(res) // 输出:[[1 2] [2 3] [3 4] [4 5]]
}
func slidingWindow(size int, input []int) [][]int {
// 返回入参的切片作为第一个元素
if len(input) <= size {
return [][]int{input}
}
// 以所需的精确大小分配切片
r := make([][]int, 0, len(input)-size+1)
for i, j := 0, size; j <= len(input); i, j = i+1, j+1 {
r = append(r, input[i:j])
}
return r
}
参考资料
1、https://mp.weixin.qq.com/s/362m-GsKqLmrh5kbHp4Maw