从 GO 切片中删除项目的正确方法是什么?
此外,重新初始化切片的正确方法是什么,即完全清空它但仍然保留它?
我相信你误解了切片的性质。切片就像ArrayList
Java 中的一个。它由常规阵列支持,并根据需要增长/缩小。切片上的操作具有与您对ArrayList
.
LinkedList
如果切片是等效的,您的问题会更有意义。为此,请查找Package list。
不过,这里是如何做到这一点。大多数直接来自SliceTricks,但我认为在 SO 上最好不要引用链接并在此处提供答案。
如果您不关心顺序,那么您可以使用任何编程语言在 O(1) 时间内完成此操作。如果你关心订单,这是行不通的。
这个想法是用切片中的最后一个项目覆盖要删除的项目,然后将切片的大小减小一个。
arr := []string{ "allo", "hello", "bye", "chao" }
// delete "bye"
deleteIdx := 2
lastIdx := len(arr) - 1
// arr = { "allo", "hello", "chao", "chao" }
arr[deleteIdx] = arr[lastIdx]
// arr = { "allo", "hello", "chao" } ... "chao"
arr = arr[:lastIdx - 1]
arr[deleteIdx], arr = arr[len(arr)-1], arr[:len(arr) - 1]
但是,就像 SliceTricks 文章中提到的那样,如果您不这样做,某些类型的值将不会被垃圾收集nil
,因为切片后面的支持数组仍然持有对它们的引用。解决方案是在nil
他们进行操作时。
arr[len(arr)-1], arr[deleteIdx], arr = nil, arr[len(arr)-1], arr[:len(arr)-1]
// ^ Setting the deleted index to nil ^
当然,如果您不关心维护秩序,这就是全部。如果您确实关心,则需要在重新deleteIdx
开始后复制所有内容deleteIdx
,即 O(n)。如果您发现自己正在这样做,请考虑是否没有更好的数据结构来满足您的需求。
// Copy everything from [deleteIdx+1 .. n) onto [deleteIdx .. )
copy(arr[deleteIdx:], arr[deleteIdx+1:])
// arr[n - 1] and arr[n] have the same value (n = len(arr) - 1)
arr[len(arr)-1] = nil
// re-slice to reference only the n-1 elements
arr = arr[:len(arr)-1]
您可以通过重新切片所有项目来重新初始化切片
// Keep everything from [0 .. 0), which means keep nothing
arr = arr[:0]
但是这样做有一个问题:如上所述,切片的支持数组仍将引用切片中的原始项目。相反,您应该做的是创建一个新切片并让这个切片被垃圾收集。
答案是多方面的:
a = a[:0]
reslicesa
到零长度,同时保留后备数组。