Go 如何在切片上进行扫描时从切片中删除项目?
在切片上搜索时,从切片中删除项目的最佳方法是什么 例如:Go 如何在切片上进行扫描时从切片中删除项目?,go,Go,在切片上搜索时,从切片中删除项目的最佳方法是什么 例如: type MultiDataPoint []*DataPoint func (m MultiDataPoint) Json() ([]byte, error) { for i, d := range m { err := d.clean() if ( err != nil ) { //Remove the DP from m } } retu
type MultiDataPoint []*DataPoint
func (m MultiDataPoint) Json() ([]byte, error) {
for i, d := range m {
err := d.clean()
if ( err != nil ) {
//Remove the DP from m
}
}
return json.Marshal(m)
}
比如:
m = append(m[:i], m[i+1:]...)
可能有更好的方法,但下面是一个从切片中删除偶数值的示例:
m := []int{1,2,3,4,5,6}
deleted := 0
for i := range m {
j := i - deleted
if (m[j] & 1) == 0 {
m = m[:j+copy(m[j:], m[j+1:])]
deleted++
}
}
请注意,我没有使用
I,d:=range m
语法获取元素,因为一旦您开始从切片中删除,d
将最终被设置为错误的元素。正如您在其他地方提到的,您可以分配新的内存块并仅向其复制有效的元素。但是,如果要避免分配,可以就地重写切片:
i := 0 // output index
for _, x := range s {
if isValid(x) {
// copy and increment index
s[i] = x
i++
}
}
// Prevent memory leak by erasing truncated values
// (not needed if values don't contain pointers, directly or indirectly)
for j := i; j < len(s); j++ {
s[j] = nil
}
s = s[:i]
i:=0//输出索引
对于ux:=范围s{
如果有效(x){
//复制和增量索引
s[i]=x
我++
}
}
//通过擦除截断的值防止内存泄漏
//(如果值不直接或间接包含指针,则不需要)
对于j:=i;j
完整示例:
注意,这将在底层数组中的索引
i
之后保留旧值,因此,如果值是指针或包含指针,则这将一直保留到片段本身被垃圾回收为止。您可以通过将所有值设置为nil或从i到切片结束的零值,然后再截断切片来解决此问题。另一个选项是使用切片长度使用法线for循环,并在每次删除值时从索引中减去1。请参见以下示例:
m := []int{3, 7, 2, 9, 4, 5}
for i := 0; i < len(m); i++ {
if m[i] < 5 {
m = append(m[:i], m[i+1:]...)
i-- // -1 as the slice just got shorter
}
}
我知道它的答案很久以前,但我在其他语言中使用类似的东西,但我不知道它是否是golang方式 只需从后向前迭代,就不必担心索引被删除。我用的是和亚当一样的例子
m = []int{3, 7, 2, 9, 4, 5}
for i := len(m)-1; i >= 0; i-- {
if m[i] < 5 {
m = append(m[:i], m[i+1:]...)
}
}
m=[]int{3,7,2,9,4,5}
对于i:=len(m)-1;i>=0;我--{
如果m[i]<5{
m=追加(m[:i],m[i+1:]…)
}
}
您甚至不需要倒数,但您需要检查您是否位于建议的append()
将失败的数组末尾。以下是从排序列表中删除重复正整数的示例:
// Remove repeating numbers
numbers := []int{1, 2, 3, 3, 4, 5, 5}
log.Println(numbers)
for i, numbersCount, prevNum := 0, len(numbers), -1; i < numbersCount; numbersCount = len(numbers) {
if numbers[i] == prevNum {
if i == numbersCount-1 {
numbers = numbers[:i]
} else {
numbers = append(numbers[:i], numbers[i+1:]...)
}
continue
}
prevNum = numbers[i]
i++
}
log.Println(numbers)
//删除重复的数字
数字:=[]整数{1,2,3,3,4,5,5}
log.Println(数字)
对于i,numberscont,prevNum:=0,len(数字),-1;我是数数的;numberscont=len(数字){
如果数字[i]==prevNum{
如果i==numbersCount-1{
数字=数字[:i]
}否则{
数字=附加(数字[:i],数字[i+1:]…)
}
持续
}
prevNum=数字[i]
我++
}
log.Println(数字)
操场:试试看
例如:
package main
import (
"fmt"
"sort"
)
func main() {
// Our slice.
s := []int{3, 7, 2, 9, 4, 5}
// 1. Iterate over it.
for i, v := range s {
func(i, v int) {}(i, v)
}
// 2. Sort it. (by whatever condition of yours)
sort.Slice(s, func(i, j int) bool {
return s[i] < s[j]
})
// 3. Cut it only once.
i := sort.Search(len(s), func(i int) bool { return s[i] >= 5 })
s = s[i:]
// That's it!
fmt.Println(s) // [5 7 9]
}
主程序包
进口(
“fmt”
“排序”
)
func main(){
//我们的那一片。
s:=[]int{3,7,2,9,4,5}
//1.迭代它。
对于i,v:=范围s{
func(i,v int){}(i,v)
}
//2.分类。(根据你的情况)
sort.Slice(s,func(i,j int)bool{
返回s[i]=5})
s=s[i:]
//就这样!
fmt.Println(s)/[5 7 9]
}
我刚刚实现了一个方法,它删除了slice中的所有nil元素 我用它解决了一个leetcode问题,它工作得很好
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func removeNil(lists *[]*ListNode) {
for i := 0; i < len(*lists); i++ {
if (*lists)[i] == nil {
*lists = append((*lists)[:i], (*lists)[i+1:]...)
i--
}
}
}
/**
*单链表的定义。
*类型ListNode结构{
*Val int
*下一个*列表节点
* }
*/
func removeNil(列表*[]*列表节点){
对于i:=0;i
这里有一种更惯用的方法来从片中删除元素
temp := s[:0]
for _, x := range s {
if isValid(x) {
temp = append(temp, x)
}
}
s = temp
游乐场连接:
注意:示例和游乐场链接基于@tomasz的答案。@YasirG.:用于从
地图中删除。OP想要从切片中删除。啊,真的很抱歉,错误的答案已经醒了25个小时了:SGo迫切需要一个下降范围构造。没有它会导致大量的额外工作。这会改变什么呢@Vector虽然我刚刚意识到,仅仅创建第二个多数据点对象,向其添加有效的内容,并封送它,是非常直接的(可能效率更低?)。我不知道为什么我一开始没有看到这一点:-/我想效率取决于预期的删除与元素总数的比率。不过,代码很可能更直接。对于i来说,
应该是对于i:=
@newacct:Oops。已编辑。对于i:=0,应使用形式;i
对于循环,范围可能会给您一个索引超出范围的错误。值得注意的是:我试图在字符串片上使用此方法-我得到此错误:“不能在append中使用m[i+1:](type[]string)作为类型字符串”第二个参数似乎是一个字符串而不是一片字符串。有什么想法吗?Nvmd-我刚刚意识到“…”实际上是代码的一部分。如果在迭代m
时使用此参数,您将得到运行时错误:切片超出范围
。这就是问题所在。您可以使用m=append(m[:I],m][i+1:]…)
从切片中删除项目,但在使用i的进行迭代时不删除,元素:=范围m
。在Go@Ectomorph然后,我是一个C++程序员——幸好这些日子已经过去了,用它们来分号。应该是被接受的答案。比每次删除时复制数组要好得多。@masz你愿意详细说明你的注释的含义吗?它会留下一些垃圾句子吗?@EugeneBeresovsky我认为我的措辞不太准确,我唯一的意图是警告人们我们正在覆盖原始数组,所以可能会有副作用。将进行编辑。问得好,但我想不起为什么会有。可能只是为了展示某种功能作为一个
temp := s[:0]
for _, x := range s {
if isValid(x) {
temp = append(temp, x)
}
}
s = temp