Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Golang切片元素的就地删除_Go_Slice_In Place - Fatal编程技术网

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的解决方案呢?它似乎不那么复杂。它只是替换指针。但事实并非如此,是吗?那有关系吗?