小程序开发定制Golang 切片删除指定元素的几种方法

文章目录


Go 小程序开发定制并没有提供删除切片元小程序开发定制素专用的语法或函数,小程序开发定制需要使用切片本身的特小程序开发定制性来删除元素。

小程序开发定制删除切片指定元素一般有如下几种方法,本文以 []int 为例给出具体实现。

1.截取法(修改原切片)

这里利用对 的截取删除指定元素。注意删除时,后面的元素会前移,所以下标 i 应该左移一位。

// DeleteSlice1 删除指定元素。func DeleteSlice1(a []int, elem int) []int {	for i := 0; i < len(a); i++ {		if a[i] == elem {			a = append(a[:i], a[i+1:]...)			i--		}	}	return a}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

2.拷贝法(不改原切片)

这种方法最容易理解,重新使用一个 slice,将要删除的元素过滤掉。缺点是需要开辟另一个 slice 的空间,优点是容易理解,而且不会修改原 slice。

// DeleteSlice2 删除指定元素。func DeleteSlice2(a []int, elem int) []int {	tmp := make([]int, 0, len(a))	for _, v := range a {		if v != elem {			tmp = append(tmp, v)		}	}	return tmp}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.移位法(修改原切片)

3.1 方式一

利用一个下标 index,记录下一个有效元素应该在的位置。遍历所有元素,当遇到有效元素,将其移动到 index 且 index 加一。最终 index 的位置就是所有有效元素的下一个位置,最后做一个截取就行了。这种方法会修改原来的 slice。

该方法可以看成对第一种方法截取法的改进,因为每次指需移动一个元素,性能更加。

// DeleteSlice3 删除指定元素。func DeleteSlice3(a []int, elem int) []int {	j := 0	for _, v := range a {		if v != elem {			a[j] = v			j++		}	}	return a[:j]}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3.2 方式二

创建了一个 slice,但是共用原始 slice 的底层数组。这样也不需要额外分配内存空间,直接在原 slice 上进行修改。

// DeleteSlice4 删除指定元素。func DeleteSlice4(a []int, elem int) []int {	tgt := a[:0]	for _, v := range a {		if v != elem {			tgt = append(tgt, v)		}	}	return tgt}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4.性能对比

假设我们的切片有 0 和 1,我们要删除所有的 0。

这里分别对长度为 10、100、1000 的切片进行测试,来上下上面四种实现的性能差异。

生成切片函数如下:

func getSlice(n int) []int {	a := make([]int, 0, n)	for i := 0; i < n; i++ {		if i%2 == 0 {			a = append(a, 0)			continue		}		a = append(a, 1)	}	return a}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

基准测试代码如下:

func BenchmarkDeleteSlice1(b *testing.B) {	for i := 0; i < b.N; i++ {		_ = DeleteSlice1(getSlice(10), 0)	}}func BenchmarkDeleteSlice2(b *testing.B) {	for i := 0; i < b.N; i++ {		_ = DeleteSlice2(getSlice(10), 0)	}}func BenchmarkDeleteSlice3(b *testing.B) {	for i := 0; i < b.N; i++ {		_ = DeleteSlice3(getSlice(10), 0)	}}func BenchmarkDeleteSlice4(b *testing.B) {	for i := 0; i < b.N; i++ {		_ = DeleteSlice4(getSlice(10), 0)	}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

测试结果如下:
原切片长度为 10:

go test -bench=. main/slicegoos: windowsgoarch: amd64pkg: main/slicecpu: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHzBenchmarkDeleteSlice1-8         17466486                65.07 ns/opBenchmarkDeleteSlice2-8         14897282                85.22 ns/opBenchmarkDeleteSlice3-8         21952129                50.78 ns/opBenchmarkDeleteSlice4-8         22176390                54.68 ns/opPASSok      main/slice      5.427s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

原切片长度为 100:

BenchmarkDeleteSlice1-8          1652146               762.1 ns/opBenchmarkDeleteSlice2-8          2124237               578.4 ns/opBenchmarkDeleteSlice3-8          3161318               359.9 ns/opBenchmarkDeleteSlice4-8          2714158               423.7 ns/op
  • 1
  • 2
  • 3
  • 4

原切片长度为 1000:

BenchmarkDeleteSlice1-8            56067             21915 ns/opBenchmarkDeleteSlice2-8           258662              5007 ns/opBenchmarkDeleteSlice3-8           432049              2724 ns/opBenchmarkDeleteSlice4-8           325194              3615 ns/op
  • 1
  • 2
  • 3
  • 4

5.小结

从基准测试结果来看,性能最佳的方法是移位法,其中又属第一种实现方式较佳。性能最差的也是最常用的方法是截取法。随着切片长度的增加,上面四种删除方式的性能差异会愈加明显。

实际使用时,我们可以根据不用场景来选择。如不能修改原切片使用拷贝法,可以修改原切片使用移位法中的第一种实现方式。


参考文献


网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发