从GO中的切片中删除项目的正确方法是什么?
此外,重新初始化切片的正确方法是什么,即完全清空它但仍然保留它?
答案 0 :(得分:2)
我相信你误解了切片的本质。切片就像Java中的ArrayList
。它由常规阵列支持,并根据需求增长/缩小。切片上的操作具有与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]
你可以in a single step (SliceTricks):
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]
但是这样做有一个问题:如上所述,切片的后备数组仍然会引用切片中的原始项目。你应该做的是创建一个新的切片,让这个切片被垃圾收集。
答案 1 :(得分:1)
答案很多:
a = a[:0]
在保留后备阵列的同时将a
重置为零。