首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >删除切片中的元素

删除切片中的元素
EN

Stack Overflow用户
提问于 2015-02-24 15:17:24
回答 6查看 19.4K关注 0票数 4

我在Golang是一个完全的新手,我试图根据另一个切片中的元素删除一个切片中的元素。例如:

输入切片:urlList := []string{"test", "abc", "def", "ghi"}

要删除片的元素:remove := []string{"abc", "test"}

预期输出切片:urlList := []string{"def", "ghi"}

这就是我试过的。

代码语言:javascript
运行
复制
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)
    }
}

但不像我预料的那样起作用了。我不知道我错过了什么。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2015-02-24 15:21:15

问题是,当从原始列表中删除元素时,所有后续元素都会被移动。但是range循环不知道您更改了基础片并将像往常一样增加索引,尽管在本例中不应该这样做,因为这样就可以跳过元素。

而且,由于remove列表包含两个元素,它们在原始列表中彼此相邻的是,因此第二个元素(在本例中为"abc")将不会被选中,也不会被删除。

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

代码语言:javascript
运行
复制
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)

输出:

代码语言:javascript
运行
复制
[def ghi]

注:

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

代码语言:javascript
运行
复制
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)

围棋游乐场上试一试。

替代

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

票数 9
EN

Stack Overflow用户

发布于 2015-02-24 16:26:14

也许创建一个只包含所需元素的新片段比较简单,例如:

代码语言:javascript
运行
复制
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)

}

游乐场

结果:

代码语言:javascript
运行
复制
Have to ignore : test
Have to ignore : abc
[def ghi]
票数 3
EN

Stack Overflow用户

发布于 2015-02-25 08:11:30

在迭代切片时,您必须小心。

下面是一种从切片中删除元素的常见方法,方法是在对数据进行迭代的同时压缩数据。

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

Exclude就地更新xs,这就是使用指针参数的原因。另一种方法是更新xs的支持数组,但从函数中返回切片的方式与内置append的工作方式相同。

代码语言:javascript
运行
复制
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是urls的长度,M是remove的长度。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28699485

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档