在Go中迭代时,从切片中删除条目

时间:2013-12-12 14:08:21

标签: 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
        }
    }
    return json.Marshal(m)
}

9 个答案:

答案 0 :(得分:33)

正如您在其他地方提到的,您可以分配新的内存块并仅将有效元素复制到其中。但是,如果要避免分配,可以就地重写切片:

i := 0 // output index
for _, x := range s {
    if isValid(x) {
        // copy and increment index
        s[i] = x
        i++
    }
}
s = s[:i]

完整示例:http://play.golang.org/p/FNDFswPeDJ

请注意,它会在基础数组中的索引i之后留下一些垃圾,因此请确保没有其他切片在其中使用它。

答案 1 :(得分:13)

可能有更好的方法,但这是一个从切片中删除偶数值的示例:

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最终会被设置为错误的元素。

答案 2 :(得分:11)

我知道很久以前的答案,但我在其他语言中使用这样的东西,但我不知道它是否是golang方式。

只需从后向前迭代,因此您不必担心已删除的索引。我使用的是与Adam相同的例子。

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

答案 3 :(得分:5)

另一个选项是使用切片长度的正常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
    }
}

我不知道len()是否使用了足够的资源来做出任何改变,但您也可以只运行一次并从长度值中减去:

m := []int{3, 7, 2, 9, 4, 5}

for i, s := 0, len(m); i < s; i++ {
    if m[i] < 5 {
        m = append(m[:i], m[i+1:]...)
        s--
        i--
    }
}

答案 4 :(得分:2)

类似的东西:

m = append(m[:i], m[i+1:]...)

答案 5 :(得分:1)

这是从片段中删除元素的更惯用的Go方法。

temp := s[:0]
for _, x := range s {
    if isValid(x) {
        temp = append(temp, x)
    }
}
s = temp

游乐场链接:https://play.golang.org/p/OH5Ymsat7s9

注意:示例和游乐场链接基于@tomasz的答案https://stackoverflow.com/a/20551116/12003457

答案 6 :(得分:0)

您甚至不需要向后计数,但确实需要检查您是否在阵列的末尾,建议的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)

游乐场:https://play.golang.org/p/v93MgtCQsaN

答案 7 :(得分:0)

尝试SortBinary search

示例:

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

https://play.golang.org/p/LnF6o0yMJGT

答案 8 :(得分:0)

我只是实现了一种方法,该方法可以删除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--
        }
    }
}
相关问题