Golang切片元素的就地删除
我希望以就地方式从集合中删除元素。 考虑下面的片段:Golang切片元素的就地删除,go,slice,in-place,Go,Slice,In Place,我希望以就地方式从集合中删除元素。 考虑下面的片段: package main import "fmt" type Ints []int func (xs Ints) Filter() { for i := 0; i < len(xs); i++ { if xs[i]%2 == 0 { // Or some other filtering function xs = append(xs[:i], xs[i+1:]...)
package main
import "fmt"
type Ints []int
func (xs Ints) Filter() {
for i := 0; i < len(xs); i++ {
if xs[i]%2 == 0 { // Or some other filtering function
xs = append(xs[:i], xs[i+1:]...)
}
fmt.Printf("i %+v\n", i)
fmt.Printf("xs %+v\n", xs)
}
}
func main() {
a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
fmt.Printf("initial a %+v\n", a)
a.Filter()
fmt.Printf("final a %+v\n", a)
}
主程序包
输入“fmt”
输入Ints[]int
func(xs Ints)过滤器(){
对于i:=0;i
令人惊讶的结果是:final a[1 3 5 7 9 10 10 10 10]
我想知道怎么做。我非常确定接收器需要是指向
Ints
的指针。但这在一定程度上会弄乱代码(在所有地方都添加*xs
,可能带有括号),但更重要的是,它会产生相同的结果。我会通过移动元素、调整切片大小和使用指针来实现。大概是这样的:
package main
import "fmt"
type Ints []int
func (xs *Ints) Filter() {
filterPos := 0
for i := 0; i < len(*xs); i++ {
if (*xs)[i]%2 == 0 { // Or some other filtering function
(*xs)[filterPos] = (*xs)[i]
filterPos++
}
}
(*xs) = (*xs)[:filterPos]
}
func main() {
a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
fmt.Printf("initial a %+v\n", a)
a.Filter()
fmt.Printf("final a %+v\n", a)
}
主程序包
输入“fmt”
输入Ints[]int
func(xs*Ints)过滤器(){
过滤器组件:=0
对于i:=0;i
您必须在此处使用指针。如果您不喜欢在每个地方添加*xs,只需使用一个temp变量来执行所有操作,然后将其设置回原来的值。这是代码您的代码几乎正确
第一个错误是在删除元素时需要避免执行i++
,否则i++
会跳过下一个未读元素。这就是为什么我把它放在else
子句中
第二个错误是xs
是Filter
函数的局部变量,因此如果您更改它指向的内容(使用xs=…
),则不会更改a
指向main
内部的内容。您可以通过将其设置为指针(*xs
,正如其他人所发布的)或返回新的过滤切片来解决此问题,正如我在下面所做的那样
package main
import "fmt"
type Ints []int
func (xs Ints) Filtered() Ints {
for i := 0; i < len(xs); {
if xs[i]%2 == 0 {
xs = append(xs[:i], xs[i+1:]...)
} else {
i++
}
}
return xs
}
func main() {
a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
b := a.Filtered()
fmt.Println(b)
}
主程序包
输入“fmt”
输入Ints[]int
func(xs int)Filtered()int{
对于i:=0;i
只是一个小小的建议,使用
(*xs)=(*xs)[:filterPos:filterPos]
来修剪切片并释放额外的内存,对于较大的对象,这可能是一个相当大的内存量。@其中一个是真的,这取决于您是在优化速度还是内存。我实际上只是创建一个新的片,并保持所有内容不变,除非这是一个巨大的内存块。@其中一个我想知道如何在运行时实现它(没有时间读取它…)。它是创建一个新的底层内存缓冲区还是对其调用realloc?第二个选项速度快得多,但可能会导致内存碎片。我不确定,但我们知道它不会创建新数组,因为它的地址相同。那么@chendesheng的解决方案呢?它似乎不那么复杂。它只是替换指针。但事实并非如此,是吗?那有关系吗?