-1

I have the following code:

func TestRemoveElement(t *testing.T) {
    nums := []int{3, 2, 2, 3}
    result := removeElement(nums, 3)

    if result != 2 {
        t.Errorf("Expected 2, but it was %d instead.", result)
    }
}

func removeElement(nums []int, val int) int {

    for i, v := range nums {
        if v == val {
            nums = append(nums[:i], nums[i+1:]...)
        }
    }
    return len(nums)
}

The statement inside the if statement is the most popular way of replacing an element in a slice per this answer. But this fails deleting the last element due to i+1. i.e if a match is found in the last element, i+1 is out of bounds. What better way to replace elements that considers last elements?

blackgreen
  • 34,072
  • 23
  • 111
  • 129
chefcurry7
  • 4,813
  • 11
  • 28
  • 33
  • Does this answer your question? [How to remove the last element from a slice?](https://stackoverflow.com/questions/26172196/how-to-remove-the-last-element-from-a-slice) – jub0bs May 13 '22 at 08:41

2 Answers2

2

It looks like you are trying to remove all elements equal to val. One way to do this is to copy values not equal to val to the beginning of the slice:

func removeElement(nums []int, val int) []int {
    j := 0
    for _, v := range nums {
        if v != val {
            nums[j] = v
            j++
        }
    }
    return nums[:j]
}

Return the new slice instead of returning the length. It will be more convenient for the caller.

If you only want to remove the first element equal to val, then use this code:

func removeElement(nums []int, val int) []int {
    for i, v := range nums {
        if v == val {
            return append(nums[:i], nums[i+1:]...)
        }
    }
    return nums
}
Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242
  • excellent answer, i would give you the star but i typically award the person with "almost" as good answer but with lower points. thanks again – chefcurry7 Sep 05 '17 at 02:23
1

Adding an index check solves your issue. Copy has better performance than append but your original append version will still work. https://gist.github.com/xogeny/b819af6a0cf8ba1caaef

If you are working with slices this is a good page to have in your Go arsenal https://github.com/golang/go/wiki/SliceTricks

Also note that the function below doesn't update the slice you passed in, so while it will print how many items where removed, the original slice will not have those items removed.

func removeElement(nums []int, val int) int {
    var i int
    for {
        if i == len(nums) {
            break
        }

        if nums[i] == val {
            nums = nums[:i+copy(nums[i:], nums[i+1:])]
            i = 0
        }
        i++
    }
    return len(nums)
}

Modified removeElements that also returns the modded list

func removeElement(nums []int, val int) (numberOfItemsRemoved int, newArr []int) {
    var i int
    for {
        if i == len(nums) {
            break
        }

        if nums[i] == val {
            nums = nums[:i+copy(nums[i:], nums[i+1:])]
            i = 0
        }
        i++
    }
    return len(nums), nums
}

https://goplay.space/#1yfhTkZC4o

You can also modify the original slice by reference so that it doesn't have to be returned

func removeElement(nums *[]int, val int) int {
    var i int
    for {
        if i == len(*nums) {
            break
        }
        slice := (*nums)
        if slice[i] == val {
            slice = slice[:i+copy(slice[i:], slice[i+1:])]
            *nums = slice
            i = 0
        }
        i++
    }
    return len(*nums)
}

Example usage https://goplay.space/#leulqgwsjc

reticentroot
  • 3,612
  • 2
  • 22
  • 39