Reputation: 21957
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?
Upvotes: 24
Views: 36166
Reputation: 41
To remove a particular slice from a struct we need to run a for-loop to find that particular slice and delete it
for example:
type variable struct {
Id int `json:"id"`
Message string `json:"message"`
}
var mssg = []variable{
{Id: 1, Message: "success"},
{Id: 2, Message: "failed"}
}
for i, a := range mssg {
if a.Message == "success" {
mssg = append(mssg[:i], mssg[i+1:]...)
fmt.Println(mssg)
}
Upvotes: 0
Reputation: 4703
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
Upvotes: 1
Reputation: 41
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
}
Upvotes: 4
Reputation: 417682
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:]...)
}
}
Upvotes: 47
Reputation: 587
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:]...)
Upvotes: 7