Удалить записи из фрагмента, итерации над ним в 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)
}

Ответ 1

Как вы уже упоминали в другом месте, вы можете выделить новый блок памяти и скопировать в него только действительные элементы. Однако, если вы хотите избежать выделения, вы можете переписать свой фрагмент на месте:

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 в базовом массиве, поэтому убедитесь, что в нем нет других срезов.

Ответ 2

Там могут быть лучшие способы, но вот пример, который удаляет четные значения из среза:

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 в конечном итоге будет настроен на неправильные элементы после того, как вы начнете удаление из среза.

Ответ 3

Я знаю, что его ответ давно, но я использую что-то подобное на других языках, но я не знаю, является ли это способом 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:]...)
    }
}

Ответ 4

Другим вариантом является использование цикла normal для использования длины среза и вычитания 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--
    }
}

Ответ 5

Что-то вроде:

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

Ответ 6

Вам даже не нужно считать в обратном направлении, но вам нужно проверить, что вы находитесь в конце массива, где предложенный метод 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

Попробуйте сортировку и бинарный поиск.

Пример:

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 it!
    fmt.Println(s) // [5 7 9]
}

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

Ответ 8

Я просто реализую метод, который удаляет все нулевые элементы в слайсе.

И я использовал его для решения проблем с 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--
        }
    }
}

Ответ 9

Вот более идиоматичный способ удаления элементов из фрагментов.

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

Ссылка на игровую площадку: https://play.golang.org/p/OH5Ymsat7s9

Примечание: ссылки на примеры и игровые площадки основаны на ответе @tomasz fooobar.com/info/544385/...