Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove multiple items from a slice

Tags:

slice

go

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?

like image 431
Andrii Yurchuk Avatar asked Nov 13 '13 12:11

Andrii Yurchuk


2 Answers

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

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-- // Since we just deleted a[i], we must redo that index
        }
    }
    fmt.Println(a)
}

Playground

like image 107
ANisus Avatar answered Sep 24 '22 19:09

ANisus


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 (
    "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)
}

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

like image 29
LeGEC Avatar answered Sep 24 '22 19:09

LeGEC