从切片中删除多个项

huangapple go评论98阅读模式
英文:

Remove multiple items from a slice

问题

我正在尝试使用这里的删除示例从一个切片中删除多个项:http://code.google.com/p/go-wiki/wiki/SliceTricks
这是我写的代码:

package main

import "fmt"
import "net"

func main() {
    a := []string{"72.14.191.202", "69.164.200.202", "72.14.180.202", "2600:3c00::22", "2600:3c00::32", "2600:3c00::12"}
    fmt.Println(a)
    for index, element := range a {
        if net.ParseIP(element).To4() == nil {
            //a = append(a[:index], a[index+1:]...)
            a = a[:index+copy(a[index:], a[index+1:])]
        }
    }
    fmt.Println(a)
}

当切片中有多个IPv6地址时,这段代码无法正常工作。它会出现"panic: runtime error: slice bounds out of range"的错误。我应该如何修改这段代码,以便能够删除所有IPv6地址?

英文:

I am trying to remove multiple items from a slice by using the Delete examples from here: http://code.google.com/p/go-wiki/wiki/SliceTricks
Here is the code I have:

package main

import "fmt"
import "net"

func main() {
	a := []string{"72.14.191.202", "69.164.200.202", "72.14.180.202", "2600:3c00::22", "2600:3c00::32", "2600:3c00::12"}
	fmt.Println(a)
	for index, element := range a {
		if net.ParseIP(element).To4() == nil {
			//a = append(a[:index], a[index+1:]...)
			a = a[:index+copy(a[index:], a[index+1:])]
		}
	}
	fmt.Println(a)
}

While the code works fine if I have only one IPv6 address in the slice, it fails if there are more than one IPv6 address. It fails with the error "panic: runtime error: slice bounds out of range". What should I do to fix this code so it's able to delete all IPv6 addresses?

答案1

得分: 18

你的问题是你正在修改你正在迭代的切片。下面是稍作修改的代码:

package main

import (
	"fmt"
	"net"
)

func main() {
	a := []string{"72.14.191.202", "69.164.200.202", "72.14.180.202", "2600:3c00::22", "2600:3c00::32", "2600:3c00::12"}
	fmt.Println(a)
	for i := 0; i < len(a); i++ {
		if net.ParseIP(a[i]).To4() == nil {
			a = append(a[:i], a[i+1:]...)
			//a = a[:i+copy(a[i:], a[i+1:])]
			i-- // 由于我们刚刚删除了a[i],我们必须重新处理该索引
		}
	}
	fmt.Println(a)
}

Playground

英文:

Your problem is that you are modifying the slice that you are iterating over. Below is your code a bit modified:

package main

import (
	&quot;fmt&quot;
	&quot;net&quot;
)

func main() {
	a := []string{&quot;72.14.191.202&quot;, &quot;69.164.200.202&quot;, &quot;72.14.180.202&quot;, &quot;2600:3c00::22&quot;, &quot;2600:3c00::32&quot;, &quot;2600:3c00::12&quot;}
	fmt.Println(a)
	for i := 0; i &lt; len(a); i++ {
		if net.ParseIP(a[i]).To4() == nil {
			a = append(a[:i], a[i+1:]...)
			//a = a[:i+copy(a[i:], a[i+1:])]
			i-- // Since we just deleted a[i], we must redo that index
		}
	}
	fmt.Println(a)
}

Playground

答案2

得分: 4

只是提出一点:在迭代的结构上进行修改总是很棘手的。
避免这种情况的常见方法是在一个新变量中构建最终结果:

package main

import (
	"fmt"
	"net"
)

func main() {
	a := []string{"72.14.191.202", "69.164.200.202", "72.14.180.202", "2600:3c00::22", "2600:3c00::32", "2600:3c00::12"}
	fmt.Println(a)

	var b []string
	for _, ip := range a {
		if net.ParseIP(ip).To4() != nil {
			b = append(b, ip)
		}
	}
	fmt.Println(b)
}

点击此处查看代码

英文:

Just to raise the point : it is always tricky to alter the structure on which you are iterating.
A common way to avoid this is to build the end result in a new variable :

package main

import (
	&quot;fmt&quot;
	&quot;net&quot;
)

func main() {
	a := []string{&quot;72.14.191.202&quot;, &quot;69.164.200.202&quot;, &quot;72.14.180.202&quot;, &quot;2600:3c00::22&quot;, &quot;2600:3c00::32&quot;, &quot;2600:3c00::12&quot;}
	fmt.Println(a)

	var b []string
	for _, ip := range a {
		if net.ParseIP(ip).To4() != nil {
		        b = append(b, ip)
		}
	}
	fmt.Println(b)
}

http://play.golang.org/p/7CLMPw_FQi

huangapple
  • 本文由 发表于 2013年11月13日 20:36:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/19953963.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定