How to remove element of struct array in loop in golang

27,770

Solution 1

Quoting from the Slice Tricks page deleting the element at index i:

a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]

Note that if you plan to delete elements from the slice you're currently looping over, that may cause problems. And it does if the element you remove is the current one (or a previous element already looped over) because after the deletion all subsequent elements are shifted, but the range loop does not know about this and will still increment the index and you skip one element.

You can avoid this by using a downward loop:

for i := len(config.Applications) - 1; i >= 0; i-- {
    application := config.Applications[i]
    // Condition to decide if current element has to be deleted:
    if haveToDelete {
        config.Applications = append(config.Applications[:i],
                config.Applications[i+1:]...)
    }
}

Solution 2

You are getting this error because you are doing a loop over a slice with an inital range of X length that became X-n because you remove some elements during loop.

If you want to delete an item at a specific index from a slice, you can do it this way:

sliceA = append(sliceA[:indexOfElementToRemove], sliceA[indexOfElementToRemove+1:]...)

Solution 3

This question is a bit older but I haven't found another answer on StackOverflow which mentions the following trick from the Slice Tricks to filter a list:

b := a[:0]
for _, x := range a {
    if f(x) {
        b = append(b, x)
    }
}

So in this case a function which deletes certain elements could look like this:

func removeApplications(apps []Applications) []Applications {
    filteredApps := apps[:0]
    for _, app := apps {
        if !removeApp {
            filteredApps = append(filteredApps, app)
        }
    }
    return filteredApps
}

Solution 4

I think the simple way is

var (
  slice = []int{1,2,3,4,5}
  pos int
)
    for _, i := range slice {
        if i == 3 {
            slice = append(slice[:pos], slice[pos+1:]...)
            if pos > 0 {
                pos = pos - 1
            }
            continue
        }
        pos++
    }

here is... https://play.golang.org/p/pK3B5Mii9k

Share:
27,770

Related videos on Youtube

Alex Pliutau
Author by

Alex Pliutau

Updated on July 13, 2022

Comments

  • Alex Pliutau
    Alex Pliutau almost 2 years

    Problem

    I have array of structs:

    type Config struct {
      Applications []Application
    }
    

    Note: Config - is a struct for json.Decode.

    config = new(Config)
    _ = decoder.Decode(&config)
    

    In loop I have some condition and element deletion by key.

    for i, application := range config.Applications {
      if i == 1 {
        config.Applications = _removeApplication(i, config.Applications)
      }
    }
    
    func _removeApplication(i int, list []Application) []Application {
      if i < len(list)-1 {
        list = append(list[:i], list[i+1:]...)
      } else {
        log.Print(list[i].Name)
        list = list[:i]
      }
    
      return list
    }
    

    But always I have "out of range" error. What is the best way to delete element by key from array of structs?

  • icza
    icza almost 8 years
    @Michael The ... tells that you have a slice which you want to pass to be the value of the variadic parameter. append() has a variadic parameter which is normally called by enumerating the elements, but in this case we call it by having the elements in a slice and passing that slice, and we want the elements of the slice to be the values of the variadic parameter (and we don't want the slice itself to be a single element for the variadic parameter).
  • Alec Istomin
    Alec Istomin about 4 years
    break from the loop, since you want to delete a single element ?