3

从 GO 切片中删除项目的正确方法是什么?

此外,重新初始化切片的正确方法是什么,即完全清空它但仍然保留它?

4

2 回答 2

3

我相信你误解了切片的性质。切片就像ArrayListJava 中的一个。它由常规阵列支持,并根据需要增长/缩小。切片上的操作具有与您对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]

您可以一步完成 (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]

但是这样做有一个问题:如上所述,切片的支持数组仍将引用切片中的原始项目。相反,您应该做的是创建一个新切片并让这个切片被垃圾收集。

于 2013-08-05T03:53:20.350 回答
1

答案是多方面的:

  1. 你必须意识到没有后备数组就没有切片,如果你谈论切片,你总是必须考虑后备数组。稍微思考一下这会导致......
  2. 问题的第二部分“重新初始化一个切片,即完全清空它但仍然保留它”非常不清楚。不要以这种方式考虑切片。a = a[:0]reslicesa到零长度,同时保留后备数组。
  3. 对于其他一切:查看“官方”切片技巧https://code.google.com/p/go-wiki/wiki/SliceTricks
于 2013-08-04T23:52:41.410 回答