如何在Go语言中的循环中删除结构数组的元素

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

How to remove element of struct array in loop in golang

问题

问题

我有一个结构体数组:

type Config struct {
  Applications []Application
}

注意:Config是用于json.Decode的结构体。

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

在循环中,我有一些条件和通过键删除元素的操作。

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
}

但是我总是遇到"out of range"错误。从结构体数组中删除元素的最佳方法是什么?

英文:

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?

答案1

得分: 47

Slice Tricks页面引用删除索引为i的元素的代码段:

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

请注意,如果您计划从当前正在循环遍历的切片中删除元素,可能会引起问题。如果您删除的元素是当前元素(或已经循环遍历过的先前元素),那么在删除后,所有后续元素都会被移动,但range循环不知道这一点,仍然会增加索引,导致跳过一个元素。

您可以通过使用向下循环来避免这个问题:

for i := len(config.Applications) - 1; i >= 0; i-- {
    application := config.Applications[i]
    // 判断是否需要删除当前元素的条件:
    if haveToDelete {
        config.Applications = append(config.Applications[:i],
                config.Applications[i+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:]...)
	}
}

答案2

得分: 7

你之所以遇到这个错误,是因为你在一个初始长度为X的切片上进行循环,但在循环过程中删除了一些元素,导致切片的长度变为X-n。

如果你想从切片中删除特定索引处的元素,可以按照以下方式进行操作:

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

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:]...)

答案3

得分: 4

这个问题有点旧,但我在StackOverflow上没有找到其他提到以下技巧的答案,这个技巧来自于Slice Tricks,用于过滤列表:

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

所以在这种情况下,一个删除特定元素的函数可以像这样:

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

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
}

答案4

得分: 1

我认为简单的方法是:

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++
}

这是一个示例链接:
https://play.golang.org/p/pK3B5Mii9k

英文:

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

答案5

得分: 0

要从结构体中删除特定的切片,我们需要运行一个for循环来查找该特定的切片并删除它。

例如:

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

以上代码会删除mssg切片中Message字段为"success"的结构体。

英文:

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

huangapple
  • 本文由 发表于 2015年3月12日 17:20:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/29005825.html
匿名

发表评论

匿名网友

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

确定