What is the best way to remove items from a slice while ranging over it?

For example:

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

9 Answers

As you have mentioned elsewhere, you can allocate new memory block and copy only valid elements to it. However, if you want to avoid the allocation, you can rewrite your slice in-place:

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] 

Full example:

Note this will leave old values after index i in the underlying array, so this will leak memory until the slice itself is garbage collected, if values are or contain pointers. You can solve this by setting all values to nil or the zero value from i until the end of the slice before truncating it.

6

I know its answered long time ago but i use something like this in other languages, but i don't know if it is the golang way.

Just iterate from back to front so you don't have to worry about indexes that are deleted. I am using the same example as 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:]...) } } 
2

There might be better ways, but here's an example that deletes the even values from a slice:

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

Note that I don't get the element using the i, d := range m syntax, since d would end up getting set to the wrong elements once you start deleting from the slice.

5

One other option is to use a normal for loop using the length of the slice and subtract 1 from the index each time a value is removed. See the following example:

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

I don't know if len() uses enough resources to make any difference but you could also run it just once and subtract from the length value too:

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

Here is a more idiomatic Go way to remove elements from slices.

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

Playground link:

Note: The example and playground links are based upon @tomasz's answer

4

Something like:

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

You don't even need to count backwards but you do need to check that you're at the end of the array where the suggested append() will fail. Here's an example of removing duplicate positive integers from a sorted list:

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

Playground:

I just implement a method which removes all nil elements in slice.

And I used it to solve a leetcode problems, it works perfectly.

/** * 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-- } } } 

Try Sort and Binary search.

Example:

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

2

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy