删除切片元素并重新初始化切片

时间:2013-08-04 23:02:31

标签: go

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

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

2 个答案:

答案 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)

答案很多:

  1. 您必须意识到没有支持数组的没有切片,如果您谈论切片,您也必须考虑支持数组。对此有所了解导致......
  2. 问题的第二部分“重新初始化切片,即完全清空它但仍然保留它”是非常不清楚的。不要以这种方式考虑切片。 a = a[:0]在保留后备阵列的同时将a重置为零。
  3. 其他一切:看看“官方”切片技巧https://code.google.com/p/go-wiki/wiki/SliceTricks