为了账号安全,请及时绑定邮箱和手机立即绑定

删除切片中的元素

删除切片中的元素

Go
温温酱 2021-09-13 20:15:25
我是 Golang 的完全新手,我试图根据另一个切片中的元素删除一个切片中的元素。例如输入切片: urlList := []string{"test", "abc", "def", "ghi"}要删除切片的元素: remove := []string{"abc", "test"}预期输出切片: urlList := []string{"def", "ghi"}这是我尝试过的。func main() {    urlList := []string{"test", "abc", "def", "ghi"}    remove := []string{"abc", "test"}loop:    for i, url := range urlList {        for _, rem := range remove {            if url == rem {                urlList = append(urlList[:i], urlList[i+1:]...)                continue loop            }        }    }    for _, v := range urlList {        fmt.Println(v)    }}但它并没有像我预期的那样工作。我不知道我错过了什么。
查看完整描述

3 回答

?
白衣非少年

TA贡献1155条经验 获得超0个赞

问题在于,当您从原始列表中删除一个元素时,所有后续元素都将被shift。但是range循环不知道您更改了底层切片并且会像往常一样增加索引,即使在这种情况下它不应该因为您跳过一个元素。


并且由于该remove列表包含 2 个在原始列表中彼此相邻的元素,因此"abc"不会检查第二个(在这种情况下)也不会被删除。


一种可能的解决方案是不range在外循环中使用,当您删除一个元素时,您手动减少索引,i--因为继续下一次迭代它将自动增加:


urlList := []string{"test", "abc", "def", "ghi"}

remove := []string{"abc", "test"}


loop:

for i := 0; i < len(urlList); i++ {

    url := urlList[i]

    for _, rem := range remove {

        if url == rem {

            urlList = append(urlList[:i], urlList[i+1:]...)

            i-- // Important: decrease index

            continue loop

        }

    }

}


fmt.Println(urlList)

输出:


[def ghi]

笔记:


由于外循环在内循环之后不包含任何内容,因此您可以用简单的 替换 label+continue break:


urlList := []string{"test", "abc", "def", "ghi"}

remove := []string{"abc", "test"}


for i := 0; i < len(urlList); i++ {

    url := urlList[i]

    for _, rem := range remove {

        if url == rem {

            urlList = append(urlList[:i], urlList[i+1:]...)

            i-- // Important: decrease index

            break

        }

    }

}


fmt.Println(urlList)

在Go Playground上试试。


选择


对此的替代方法是外循环向下,因此无需手动减少(或增加)索引变量,因为移位的元素不受影响(由于向下方向已被处理)。


查看完整回答
反对 回复 2021-09-13
?
慕标5832272

TA贡献1966条经验 获得超4个赞

也许创建一个新切片更简单,它只包含您想要的元素,例如:


package main


import "fmt"


func main() {

    urlList := []string{"test", "abc", "def", "ghi"}

    remove := []string{"abc", "test"}


    new_list := make([]string, 0)


    my_map := make(map[string]bool, 0)

    for _, ele := range remove {

        my_map[ele] = true

    }


    for _, ele := range urlList {

        _, is_in_map := my_map[ele]

        if is_in_map {

            fmt.Printf("Have to ignore : %s\n", ele)

        } else {

            new_list = append(new_list, ele)    

        }

    }


    fmt.Println(new_list)


}

操场


结果:


Have to ignore : test

Have to ignore : abc

[def ghi]


查看完整回答
反对 回复 2021-09-13
?
江户川乱折腾

TA贡献1851条经验 获得超5个赞

在迭代切片时修改切片时必须小心。


这是通过在迭代数据的同时压缩数据来从切片中删除元素的常用方法。


它还对排除元素使用映射而不是切片,这在排除项的数量很大时提供了效率。


Excludexs就地更新,这就是使用指针参数的原因。另一种方法是更新 的后备数组xs,但以与内置函数相同的方式从函数返回切片append。


package main


import "fmt"


func Exclude(xs *[]string, excluded map[string]bool) {

    w := 0

    for _, x := range *xs {

        if !excluded[x] {

            (*xs)[w] = x

            w++

        }

    }

    *xs = (*xs)[:w]

}


func mapFromSlice(ex []string) map[string]bool {

    r := map[string]bool{}

    for _, e := range ex {

        r[e] = true

    }

    return r

}


func main() {

    urls := []string{"test", "abc", "def", "ghi"}

    remove := mapFromSlice([]string{"abc", "test"})

    Exclude(&urls, remove)

    fmt.Println(urls)

}

此代码在运行时为 O(N+M),其中 N 是 的长度,urlsM 是 的长度remove。


查看完整回答
反对 回复 2021-09-13
  • 3 回答
  • 0 关注
  • 276 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信