Skip to content

Instantly share code, notes, and snippets.

@tappoz
Last active June 3, 2019 15:31
Show Gist options
  • Save tappoz/41f975261dc63d46431990bc31cb5bf4 to your computer and use it in GitHub Desktop.
Save tappoz/41f975261dc63d46431990bc31cb5bf4 to your computer and use it in GitHub Desktop.
How to remove in-place an element from a Go slice

Run the following code with: go test -v -run TestFooInPlace

package foo

import (
	"fmt"
	"log"
	"math/rand"
	"testing"
)

type FooItem struct {
	Id       int
	Category string
	Value    float64
}

const minRand = 0
const maxRand = 10

const maxSliceLen = 3

var inFooSlice []FooItem

func init() {
	for i := 1; i <= maxSliceLen; i++ {
		inFooSlice = append(inFooSlice, FooItem{
			Id:       i,
			Category: "FooCat",
			Value:    minRand + rand.Float64()*(maxRand-minRand),
		})
	}
}

// use a pointer for the input slice so then it is changed in-place
func FindAndRemoveFromFooSliceInPlace(iFilter int, inSl *[]FooItem) *FooItem {
	pointedInSl := *inSl // dereference the pointer so then we can use `append`
	inLen := len(pointedInSl)
	for idx, elem := range pointedInSl {
		if elem.Id == iFilter {
			log.Printf("Loop ID %v", idx)

			// check these docs: https://github.com/golang/go/wiki/SliceTricks#delete
			pointedInSl = append(pointedInSl[:idx], pointedInSl[idx+1:inLen]...)
			pointedInSl = pointedInSl[:inLen-1] // redundant instruction, but it gives the ideas
			*inSl = pointedInSl                 // assigning the new slice to the pointed value before returning

			return &elem
		}
	}
	return nil
}

func TestFooInPlace(t *testing.T) {
	originalLegth := len(inFooSlice)
	fmt.Printf("\nOriginal (PRE) slice\n")
	fmt.Println(inFooSlice)
	fmt.Println(originalLegth)
	fmt.Println(cap(inFooSlice))

	idFilter := 1

	fePtr := FindAndRemoveFromFooSliceInPlace(idFilter, &inFooSlice)

	fmt.Printf("\nOriginal (POST) slice\n")
	fmt.Println(inFooSlice)
	fmt.Println(len(inFooSlice))
	fmt.Println(cap(inFooSlice))

	fmt.Printf("\nFiltered element\n")
	fmt.Println(*fePtr)

	if originalLegth != len(inFooSlice)+1 {
		t.Errorf("Length mismatch: the original length %v, the current length %v", originalLegth, len(inFooSlice))
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment