324
fmt.Println("Enter position to delete::")
fmt.Scanln(&pos)

new_arr := make([]int, (len(arr) - 1))
k := 0
for i := 0; i < (len(arr) - 1); {
    if i != pos {
        new_arr[i] = arr[k]
        k++
        i++
    } else {
        k++
    }
}

for i := 0; i < (len(arr) - 1); i++ {
    fmt.Println(new_arr[i])
}

I am using this command to delete an element from a Slice but it is not working, please suggest.

Carson
  • 6,105
  • 2
  • 37
  • 45
Anchal Sarraf
  • 3,443
  • 2
  • 14
  • 13
  • 8
    This is good reading: https://blog.golang.org/go-slices-usage-and-internals – squiguy May 19 '16 at 21:19
  • Also this: https://www.sitepoint.com/arrays-slices-basic-oop-go/ – hkulekci May 19 '16 at 21:22
  • 2
    This question has answers with Go 1.18 and generics further below: [1](https://stackoverflow.com/a/71691201/4108803) [2](https://stackoverflow.com/a/71659369/4108803) – blackgreen May 07 '22 at 19:54

23 Answers23

461

Order matters

If you want to keep your array ordered, you have to shift all of the elements at the right of the deleting index by one to the left. Hopefully, this can be done easily in Golang:

func remove(slice []int, s int) []int {
    return append(slice[:s], slice[s+1:]...)
}

However, this is inefficient because you may end up with moving all of the elements, which is costly.

Order is not important

If you do not care about ordering, you have the much faster possibility to replace the element to delete with the one at the end of the slice and then return the n-1 first elements:

func remove(s []int, i int) []int {
    s[i] = s[len(s)-1]
    return s[:len(s)-1]
}

With the reslicing method, emptying an array of 1 000 000 elements take 224s, with this one it takes only 0.06ns.

This answer does not perform bounds-checking. It expects a valid index as input. This means that negative values or indices that are greater or equal to the initial len(s) will cause Go to panic.

Slices and arrays being 0-indexed, removing the n-th element of an array implies to provide input n-1. To remove the first element, call remove(s, 0), to remove the second, call remove(s, 1), and so on and so forth.

Jon Egerton
  • 40,401
  • 11
  • 97
  • 129
T. Claverie
  • 11,380
  • 1
  • 17
  • 28
  • @bgp This is just *popping* (removing the last element) of slice, not removing the one under index provided as is in the original question. Similarly you could *shift* (remove the first element) with `return s[1:]` which also does not answer the original question. – shadyyx Dec 07 '16 at 16:10
  • 3
    Hm, not really. This: `s[i] = s[len(s)-1]` definitely copies the last element to the element at index `i`. Then, `return s[:len(s)-1]` returns the slice without the last element. Two statements there. – Brad Peabody Dec 07 '16 at 19:02
  • 3
    Fails with len(arr) == 2 and the elem to delete is the last one: https://play.golang.org/p/WwD4PfUUjsM – zenocon Oct 21 '18 at 20:27
  • 7
    @zenocon In Golang, arrays are 0-index, meaning that valid indices for an array of length 2 are 0 and 1. Indeed, this function does not check the bounds of the array, and expects a valid index to be provided. When **len(arr) == 2**, valid arguments are thus **0** or **1**. Anything else would trigger an out of bounds access, and Go will panic. – T. Claverie Nov 01 '18 at 08:37
  • @T.Claverie oh, I know. I was just pointing out that the algo presented has a flaw. – zenocon Nov 02 '18 at 13:59
  • I think if you're going to iteratively remove nearly all of the elements, e.g. in an in-place filter, the "order matters" version has running time O(n^2), and "order doesn't matter + merge sort" takes O(n + n log n) = O(n log n). –  Jun 22 '19 at 01:53
  • 10
    Adding this for reference, for the **order does not matter** option, it's better to use `s[len(s)-1], s[i] = 0, s[len(s)-1]`. Especially so if you're working with non-primitive arrays. If you had pointers to something it's better to make the element you want to remove `nil` before slicing so you don't have pointers in the underlying array. This [answer explains why very well](https://stackoverflow.com/a/28432812/555516). In short: after moving the last element at the deleted element's location, zero the last element before slicing. – Vlad V Feb 16 '20 at 16:22
  • 17
    This is a dangerous answer and I’m guessing has introduced a few hundred bugs into programs that didn’t fully understand that this modified all references to the slice. It’s also not correct if you read through the original question which you can see wants to preserve the original slice. – michael.schuett Apr 18 '20 at 18:09
  • 1
    The issue with this answer is that you remove only the first occurrence of the element and you never remove all of them. If your slice contains duplicates, they will still be your in the slice... – eexit Jul 07 '20 at 20:25
  • 2
    @eexit Indeed, however that is a different problem than what is described in this question, which is to delete "an" element at the specified index position. – Michael Fulton Oct 29 '21 at 17:08
  • 1
    I'm getting strange behaviour on arrays/slices that are 4 or shorter with the second method or if I try to remove the last element. With `a := [5]int{1, 2, 3, 4}; b := a[:]; b = remove(b, 2)` I was expecting to result in `[1, 2, 4]` in my slice but got `[1,2,0,4]` instead: https://go.dev/play/p/SZGjzbxYbqR – apokaliptis Dec 14 '21 at 04:05
  • I'm also facing something weird calling the remove function twice with different indexes: https://go.dev/play/p/9Xyqfj22OlK Expect [1 2 3 4 5] = [1 2 3 4 5] Expect [10 3 4 5] = [1 3 4 5 5] – Elton Santana Feb 03 '22 at 04:23
  • 2
    As you're the top upvoted answer, you should add the slices.Remove (1.18) to help future users – yesennes Apr 04 '22 at 13:58
137

This is a little strange to see but most answers here are dangerous and gloss over what they are actually doing. Looking at the original question that was asked about removing an item from the slice a copy of the slice is being made and then it's being filled. This ensures that as the slices are passed around your program you don't introduce subtle bugs.

Here is some code comparing users answers in this thread and the original post. Here is a go playground to mess around with this code in.

Append based removal

package main

import (
    "fmt"
)

func RemoveIndex(s []int, index int) []int {
    return append(s[:index], s[index+1:]...)
}

func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    removeIndex := RemoveIndex(all, 5)

    fmt.Println("all: ", all) //[0 1 2 3 4 6 7 8 9 9]
    fmt.Println("removeIndex: ", removeIndex) //[0 1 2 3 4 6 7 8 9]

    removeIndex[0] = 999
    fmt.Println("all: ", all) //[999 1 2 3 4 6 7 9 9]
    fmt.Println("removeIndex: ", removeIndex) //[999 1 2 3 4 6 7 8 9]
}

In the above example you can see me create a slice and fill it manually with numbers 0 to 9. We then remove index 5 from all and assign it to remove index. However when we go to print out all now we see that it has been modified as well. This is because slices are pointers to an underlying array. Writing it out to removeIndex causes all to be modified as well with the difference being all is longer by one element that is no longer reachable from removeIndex. Next we change a value in removeIndex and we can see all gets modified as well. Effective go goes into some more detail on this.

The following example I won't go into but it does the same thing for our purposes. And just illustrates that using copy is no different.

package main

import (
    "fmt"
)

func RemoveCopy(slice []int, i int) []int {
    copy(slice[i:], slice[i+1:])
    return slice[:len(slice)-1]
}

func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    removeCopy := RemoveCopy(all, 5)

    fmt.Println("all: ", all) //[0 1 2 3 4 6 7 8 9 9]
    fmt.Println("removeCopy: ", removeCopy) //[0 1 2 3 4 6 7 8 9]

    removeCopy[0] = 999
    fmt.Println("all: ", all) //[99 1 2 3 4 6 7 9 9]
    fmt.Println("removeCopy: ", removeCopy) //[999 1 2 3 4 6 7 8 9]
}

The questions original answer

Looking at the original question it does not modify the slice that it's removing an item from. Making the original answer in this thread the best so far for most people coming to this page.

package main

import (
    "fmt"
)

func OriginalRemoveIndex(arr []int, pos int) []int {
    new_arr := make([]int, (len(arr) - 1))
    k := 0
    for i := 0; i < (len(arr) - 1); {
        if i != pos {
            new_arr[i] = arr[k]
            k++
        } else {
            k++
        }
        i++
    }

    return new_arr
}

func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    originalRemove := OriginalRemoveIndex(all, 5)

    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    fmt.Println("originalRemove: ", originalRemove) //[0 1 2 3 4 6 7 8 9]

    originalRemove[0] = 999
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    fmt.Println("originalRemove: ", originalRemove) //[999 1 2 3 4 6 7 8 9]
}

As you can see this output acts as most people would expect and likely what most people want. Modification of originalRemove doesn't cause changes in all and the operation of removing the index and assigning it doesn't cause changes as well! Fantastic!

This code is a little lengthy though so the above can be changed to this.

A correct answer

package main

import (
    "fmt"
)

func RemoveIndex(s []int, index int) []int {
    ret := make([]int, 0)
    ret = append(ret, s[:index]...)
    return append(ret, s[index+1:]...)
}

func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    removeIndex := RemoveIndex(all, 5)

    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    fmt.Println("removeIndex: ", removeIndex) //[0 1 2 3 4 6 7 8 9]

    removeIndex[0] = 999
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 9 9]
    fmt.Println("removeIndex: ", removeIndex) //[999 1 2 3 4 6 7 8 9]
}

Almost identical to the original remove index solution however we make a new slice to append to before returning.

michael.schuett
  • 4,248
  • 4
  • 28
  • 39
  • 21
    this should be the answer for the question since its the only one that explains the risk of modifying the slice's backing array – JessG Apr 18 '20 at 17:59
  • 1
    `append` doesn't create a new backing array if it doesn't need to, so why should removing create a new slice? https://go.dev/play/p/8V9rbjrDkt5 – blackbox Feb 11 '22 at 20:53
  • Also see https://stackoverflow.com/questions/28115599/when-does-golang-append-create-a-new-slice – blackbox Feb 11 '22 at 21:15
  • 1
    If you read my full answer what you ask about is clearly answered. – michael.schuett Feb 12 '22 at 21:49
  • `append` will modify the backing array when there is room. Removing from a slice is creating room, so any solution that involves creating a new slice when removing is clearly wrong. – blackbox Feb 15 '22 at 03:47
  • This is better answer. The most upvoted answer changes the underlying slice in a way, that is not useful in most cases and can cause a lot of trouble. I ask you to upvote this one. However this is still not the optimal answer. The first `append()` can be replaced by `copy()` for more speed. – Blcknx Feb 13 '23 at 10:56
  • @blackbox please share a go playground example that breaks my "correct answer" provided and satisfies all the edge cases I pointed out. Thanks. – michael.schuett Aug 15 '23 at 19:41
  • @michael.schuett Your "correct answer" is the wrong answer for this question, but the correct answer for another question about how to make an immutable object that functions like slice. Your "edge cases" are yours. In most cases needlessly creating a new slice is wasteful. – blackbox Aug 29 '23 at 14:28
90

Remove one element from the Slice (this is called 're-slicing'):

package main

import (
    "fmt"
)

func RemoveIndex(s []int, index int) []int {
    return append(s[:index], s[index+1:]...)
}

func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println(all) //[0 1 2 3 4 5 6 7 8 9]
    all = RemoveIndex(all, 5)
    fmt.Println(all) //[0 1 2 3 4 6 7 8 9]
}
wasmup
  • 14,541
  • 6
  • 42
  • 58
  • 13
    Worth pointing out that this is called 're-slicing' and is relatively expensive though it is the idiomatic way to do this in Go. Just don't confuse this with an operation like removing a node from a linked list because it's not that and if you're going to do it a lot, especially with large collections, you should consider alternative designs that avoid it. – evanmcdonnal May 19 '16 at 22:24
  • Yes this is idiomatic way in Golang, and even in C/Assembly removing one random element from sorted array is expensive, you need shift (copy) all right elements one position to the left. Yes in some use case Linked List is better solution to remove random element from the List. –  May 20 '16 at 07:15
  • 4
    Note that this method causes all to be modified and now n and all point to part of the same underlying array. This is very likely to lead to bugs in your code. – michael.schuett Jul 26 '19 at 05:10
  • 1
    Getting this error `2019/09/28 19:46:25 http: panic serving 192.168.1.3:52817: runtime error: slice bounds out of range [7:5] goroutine 7 [running]:` – OhhhThatVarun Sep 28 '19 at 14:18
  • This function can cause out-of-bounds `panic()`. Please see Oleksandr's answer instead. – Vojtech Vitek - golang.cz Dec 21 '20 at 15:42
  • 7
    @STEEL are you sure about that? --> https://play.golang.org/p/IzaGUJI4qeG – Kasper Gyselinck Aug 06 '21 at 09:46
47

Using Delete from the slices package (stable since Go 1.21, on older Go versions you have to import golang.org/x/exp/slices):

slice := []int{1, 2, 3, 4}
slice = slices.Delete(slice, 1, 2)
fmt.Println(slice) // [1 3 4]

Go playground example

slices.Delete(s, i, j) removes the elements s[i:j] from s

  • i.e. the elements from and including index i up to and excluding index j
  • or if you remember math notation for intervals: [i,j)

Note two things:

  • Delete modifies the contents of the original slice
  • You need to reassign slice, otherwise it will have the wrong length
Alex80286
  • 479
  • 3
  • 3
  • 10
    It is a wrapper function for this `append(slice[:s], slice[s+1:]...)`. More info: https://cs.opensource.google/go/x/exp/+/0b5c67f0:slices/slices.go;l=156 – Tony Montana Jun 06 '22 at 09:50
  • Love this pkg! Convenient. Thanks for sharing @Alex80286 – Dele Aug 21 '22 at 10:39
  • 1
    The source code states that "Delete modifies the contents of the slice s; it does not create a new slice." but it's not obvious that you need to reassign the modified slice to update the length. This should really be highlighted. – Tom Böttger Dec 12 '22 at 20:25
  • @TomBöttger: Please help me improve my answer and let me know: What is not clear enough about the phrase "You need to reassign slice, otherwise it will have the wrong length"? – Alex80286 Dec 13 '22 at 21:51
  • 1
    @Alex80286 I'm sorry, my comment was quite ambiguous. Your answer is perfectly fine! It's good that you mention that the slice needs to be reassigned since the go source code doesn't mention it (at least not directly). – Tom Böttger Dec 13 '22 at 21:59
  • This function does not modify the backing array of the slice! Meaning the "deleted" elements are still inside the backing array. This is no different than re-indexing a slice. – Michal Przybylowicz Aug 14 '23 at 11:58
  • @MichalPrzybylowicz: Not sure if I'm misunderstanding you, but this example shows that a deleted element (2 in this case) is no longer in the backing array and that the backing array *is* modified by this function: https://go.dev/play/p/bPI1pu-R_m0 – Alex80286 Aug 24 '23 at 20:04
  • @Alex80286 I was referring to the [documentation](https://pkg.go.dev/golang.org/x/exp/slices#Delete) section for `Delete` function where it states : `Delete might not modify the elements s[len(s)-(j-i):len(s)].` - just something to keep in mind when You need to resize (upwards) slice again [eample](https://go.dev/play/p/CmJ1cgQuU-F) – Michal Przybylowicz Aug 25 '23 at 17:14
33

Minor point (code golf), but in the case where order does not matter you don't need to swap the values. Just overwrite the array position being removed with a duplicate of the last position and then return a truncated array.

func remove(s []int, i int) []int {
    s[i] = s[len(s)-1]
    return s[:len(s)-1]
}

Same result.

David
  • 439
  • 4
  • 4
  • 15
    The most readable implementation would be to copy the first element to the specified index `s[i] = s[0]`, then return an array with only the last n-1 elements. `return s[1:]` – Kent Feb 09 '17 at 21:35
  • 4
    [playground](https://play.golang.org/p/bj5OIvraAm1) of @Kent 's solution – stevenspiel Mar 16 '18 at 21:14
  • 5
    @Kent the issue with doing `s[1:]` versus `s[:len(s)-1]` is that the later will perform much better if the slice later gets `append`ed or deletes are intermingled with `append`s. The later keeps the slice capacity where-as the former doesn't. – Dave C Aug 18 '19 at 11:24
  • 1
    If you remove the 0th element with this function, it inverts the result. – ivarec Oct 27 '19 at 23:55
30

This is how you Delete From a slice the idiomatic way. You don't need to build a function it is built into the append. Try it here https://play.golang.org/p/QMXn9-6gU5P

z := []int{9, 8, 7, 6, 5, 3, 2, 1, 0}
fmt.Println(z)  //will print Answer [9 8 7 6 5 3 2 1 0]

z = append(z[:2], z[4:]...)
fmt.Println(z)   //will print Answer [9 8 5 3 2 1 0]
Yagiz Degirmenci
  • 16,595
  • 7
  • 65
  • 85
Kemar H
  • 411
  • 4
  • 2
23

From the book The Go Programming Language

To remove an element from the middle of a slice, preserving the order of the remaining elements, use copy to slide the higher-numbered elements down by one to fill the gap:

func remove(slice []int, i int) []int {
  copy(slice[i:], slice[i+1:])
  return slice[:len(slice)-1]
}
Oleksandr Mosur
  • 1,148
  • 8
  • 17
  • 7
    Note that this method causes the original slice passed in to be modified. – michael.schuett Jul 26 '19 at 05:10
  • @eatingthenight `append` can modify the backing array, so why can't remove? https://go.dev/play/p/9eQStgiqYYK – blackbox Feb 11 '22 at 21:03
  • @blackbox That's not right, append doesn't modify the backing array. Your code assigned the value of append to the backing array `s2 = append(s2, 2)` and if you omit this step, the backing array `s2` remains unchanged. Compare with https://go.dev/play/p/7EubNjwOFuD – Tom Anderson Jul 14 '22 at 02:31
  • @TomAnderson append modifies the backing array when the capacity is greater than the length will be. Here's my original example without assigning the result of append to s2 https://go.dev/play/p/mz095qeCnvL. Here's your example with a greater capacity explicitly set https://go.dev/play/p/v0JR88kuDyB. And here's a more in depth example https://go.dev/play/p/sj95rpeaJRB. – blackbox Aug 05 '22 at 22:58
  • @blackbox if you remove the `:cap(s2)` from the print statements in go.dev/play/p/v0JR88kuDyB, then it appears that s2 is not being updated. So is it safe to say that the backing array is updated, but the slice is not? – Alex Glover Aug 25 '22 at 15:25
  • @AlexGlover Yes, as long as the slice has the capacity for the appended item(s). – blackbox Aug 26 '22 at 19:02
16

I take the below approach to remove the item in slice. This helps in readability for others. And also immutable.

func remove(items []string, item string) []string {
    newitems := []string{}

    for _, i := range items {
        if i != item {
            newitems = append(newitems, i)
        }
    }

    return newitems
}
Madhan Ganesh
  • 2,273
  • 2
  • 24
  • 19
  • I like this approach better you are actually removing all occurrences of the item. – eexit Jul 07 '20 at 20:27
  • This can be easily transformed to filtering several items from the slice, nice! – eldad levy Sep 24 '20 at 12:42
  • 2
    if you have over 20k records or more this wont scale, because you will need to cycle through n times before you get - linear search wont cut it. – Dele Aug 21 '22 at 10:33
  • As Dele says above, this isn't at all scalable, but it is elegant and clean. In a production environment, you'll likely not use approaches like this, but for small environments this is fine. – Jon Nicholson Aug 21 '23 at 07:42
14

The best way to do it is to use the append function:

package main

import (
    "fmt"
)

func main() {
    x := []int{4, 5, 6, 7, 88}
    fmt.Println(x)
    x = append(x[:2], x[4:]...)//deletes 6 and 7
    fmt.Println(x)
}

https://play.golang.org/p/-EEFCsqse4u

Yagiz Degirmenci
  • 16,595
  • 7
  • 65
  • 85
TheName
  • 697
  • 1
  • 7
  • 18
13

Using generics you can pass any type of slice.

// Removes slice element at index(s) and returns new slice
func remove[T any](slice []T, s int) []T {
    return append(slice[:s], slice[s+1:]...)
}

Usage

slice := []int{1, 2, 3, 4}
result := remove(slice, 0)
fmt.Println(result)
// [2 3 4]

Example
https://go.dev/play/p/LhPGvEuZbRA

Kroksys
  • 759
  • 10
  • 15
8

The currently most voted answer by T. Claverie is correct but I find the algorithm more clear if swap is performed only if needed, i.e. for all but the last element of the slice. This can be achieved by a simple if guard.

Order is not important/ no boundary checks perfomed

func remove(s []int, i int) []int {
    // bring element to remove at the end if it's not there yet
    if i != len(s)-1 {
        s[i] = s[len(s)-1]
    }
 
    // drop the last element
    return s[:len(s)-1]
}
4

Find a way here without relocating.

  • changes order
a := []string{"A", "B", "C", "D", "E"}
i := 2

// Remove the element at index i from a.
a[i] = a[len(a)-1] // Copy last element to index i.
a[len(a)-1] = ""   // Erase last element (write zero value).
a = a[:len(a)-1]   // Truncate slice.

fmt.Println(a) // [A B E D]
  • keep order
a := []string{"A", "B", "C", "D", "E"}
i := 2

// Remove the element at index i from a.
copy(a[i:], a[i+1:]) // Shift a[i+1:] left one index.
a[len(a)-1] = ""     // Erase last element (write zero value).
a = a[:len(a)-1]     // Truncate slice.

fmt.Println(a) // [A B D E]
Franci
  • 2,157
  • 1
  • 21
  • 33
3

Maybe you can try this method:

// DelEleInSlice delete an element from slice by index
//  - arr: the reference of slice
//  - index: the index of element will be deleted
func DelEleInSlice(arr interface{}, index int) {
    vField := reflect.ValueOf(arr)
    value := vField.Elem()
    if value.Kind() == reflect.Slice || value.Kind() == reflect.Array {
        result := reflect.AppendSlice(value.Slice(0, index), value.Slice(index+1, value.Len()))
        value.Set(result)
    }
}

Usage:

arrInt := []int{0, 1, 2, 3, 4, 5}
arrStr := []string{"0", "1", "2", "3", "4", "5"}
DelEleInSlice(&arrInt, 3)
DelEleInSlice(&arrStr, 4)
fmt.Println(arrInt)
fmt.Println(arrStr)

Result:

0, 1, 2, 4, 5
"0", "1", "2", "3", "5"
Karl Doenitz
  • 2,220
  • 3
  • 20
  • 38
  • 1
    Likely because it's not idiomatic and over-engineered for what the question is asking. It's an interesting way to solve it but no one should be using this. – michael.schuett Jul 26 '19 at 04:10
  • 1
    Thanks! Actually worked just fine for me with an Interface, since this seems to be universal, maybe – Edw590 Dec 21 '19 at 13:10
  • After studying a bit more of Go, I now have a question about this. Shouldn't this not include the Array type there? Arrays can't be modified in size, like in C, so that probably won't work (it did not with me at least). I believe the function could be reduced to 2 lines (which would also partially optimize it - less variables declared and less operations to do): `var value reflect.Value = reflect.ValueOf(array).Elem(); value.Set(reflect.AppendSlice(value.Slice(0, index), value.Slice(index+1, value.Len())))`. – Edw590 Nov 10 '21 at 17:12
2
for index, item := range movies{
    if item.ID == "123"{
        movies = append(movies[:index], movies[index+1:]...)
        break
    }
}
alimkhan 7007
  • 103
  • 1
  • 5
1

Maybe this code will help.

It deletes item with a given index.

Takes the array, and the index to delete and returns a new array pretty much like append function.

func deleteItem(arr []int, index int) []int{
  if index < 0 || index >= len(arr){
    return []int{-1}
  }

    for i := index; i < len(arr) -1; i++{
      arr[i] = arr[i + 1]

    }

    return arr[:len(arr)-1]
}

Here you can play with the code : https://play.golang.org/p/aX1Qj40uTVs

MartenCatcher
  • 2,713
  • 8
  • 26
  • 39
saad hafa
  • 21
  • 2
1

In the language tutorial we learn that:

Slices are like references to arrays. A slice does not store any data, it just describes a section of an underlying array. Changing the elements of a slice modifies the corresponding elements of its underlying array.

For this reason, working with the append function on slices without taking care of the origin and destination of the values we are dealing with is very dangerous as well as wrong for the Go philosophy.

The correct solution is therefore to work with a slice referenced to a new array and not the "main" one. This is possible by creating a new slice through the make construct.

func removeAt(slice []int, index int) []int {
    newSlice := make([]int, 0) //Create a new slice of type []int and length 0
    newSlice = append(newSlice, slice[:index]...) //Copies the values contained in the old slice to the new slice up to the index (excluded)
    if index != len(slice)-1 {
        newSlice = append(newSlice, slice[index+1:]...) //If the index to be removed was different from the last one, then proceed to copy the following values of the index to the end of the old slice
    }
    return newSlice
}

In this way we are able to safely remove an element of a slice, regardless of the use we will make on the return of the function.


Since I used a function to answer the question, it would be a good idea to handle any errors as follows:

func removeAt(slice []int, index int) ([]int, error) {
    if index < 0 {
        return nil, fmt.Errorf("index (%d) cannot be a negative number", index)
    }
    if index >= len(slice) {
        return nil, fmt.Errorf("index (%d) cannot be a number greater or equal than the length of slice (%d)", index, len(slice))
    }

    newSlice := make([]int, 0)
    newSlice = append(newSlice, slice[:index]...)
    if index != len(slice)-1 {
        newSlice = append(newSlice, slice[index+1:]...)
    }
    
    return newSlice, nil
}

Or better yet, implement the function that can handle multiple types through interfaces. However, all this is a good practice since you build a function to do this, which does not concern the question posed.

However, an example of a test on the Go playground can be found here.

0

No need to check every single element unless you care contents and you can utilize slice append. try it out

pos := 0
arr := []int{1, 2, 3, 4, 5, 6, 7, 9}
fmt.Println("input your position")
fmt.Scanln(&pos)
/* you need to check if negative input as well */
if (pos < len(arr)){
    arr = append(arr[:pos], arr[pos+1:]...)
} else {
    fmt.Println("position invalid")
}
GoGo
  • 559
  • 3
  • 7
  • 14
0

You need to change your code a little bit,

new_arr := make([]int, (len(arr) - 1))
for i := 0; i < len(arr); i++ {
    if i != pos {
        new_arr = append(new_arr, arr[i])
    }
}

For a more efficient loop you can use this

for i, item := range arr {
    ...
}

At last you can do it by using native slice functionality

new_arr = append(arr[:2], arr[3:])

The last solution remove element in the index 2 and put the new slice in new_arr.

Highdeger
  • 21
  • 1
0

This is the correct and best way to delete an element from the list.Because other ways can shift the elements while deleting. So try following method if Order matters.

 func remove(s []int, index int) []int{{ return append(s[:index], s[index+1:]...) }
0

Basically you just assign to your slice the same slice but one item shorter:

data = data[:len(data)-1]

Artur Yukhatov
  • 190
  • 1
  • 9
-1

This is for remove items by value

(go 1.21)

func sliceRemove[T comparable](s *[]T, rmItems ...T) {
    var end bool
    for {
        end = true
        for i, elem := range *s {
            for _, rmData := range rmItems {
                if elem == rmData {
                    *s = slices.Delete(*s, i, i+1)
                    end = false
                    break
                }
            }
            if !end {
                break
            }
        }
        if end {
            break
        }
    }
}

func Example_sliceRemove() {
    slice := []string{"Apple", "Bar", "Foo", "Foo", "Bar", "Banana"}
    sliceRemove(&slice, "Bar", "Foo")
    fmt.Println(slice)
    // Output:
    // [Apple Banana]
}

playground

banchMark

func sliceRemove[T comparable](s *[]T, rmItems ...T) {
    var end bool
    for {
        end = true
        for i, elem := range *s {
            for _, rmData := range rmItems {
                if elem == rmData {
                    *s = slices.Delete(*s, i, i+1)
                    end = false
                    break
                }
            }
            if !end {
                break
            }
        }
        if end {
            break
        }
    }
}

func BenchmarkSliceRemoveFast(b *testing.B) {
    slice := []int{1, 2, 3, 2, 3, 4}
    for N := 0; N < b.N; N++ {
        sliceRemove(&slice, 2, 3)
    }
}

func BenchmarkSliceRemoveSlow(b *testing.B) {
    slice := []int{1, 2, 3, 2, 3, 4}
    for N := 0; N < b.N; N++ {
        rmItems := []int{2, 3}
        var newSlice []int
        for _, e := range slice {
            if !slices.Contains(rmItems, e) {
                newSlice = append(newSlice, e)
            }
        }
    }
}
go test -v -bench=BenchmarkSliceRemove -run=none -benchmem

BenchmarkSliceRemoveFast
BenchmarkSliceRemoveFast-8      123802942                9.264 ns/op           0 B/op          0 allocs/op
BenchmarkSliceRemoveSlow
BenchmarkSliceRemoveSlow-8      19463425                89.18 ns/op           24 B/op          2 allocs/op
Carson
  • 6,105
  • 2
  • 37
  • 45
-3

Since Slice is backed by an array and since there is no way you can remove an element from an array and not reshuffle memory;and I did not want to do that ugly code; here is a pseudo code to keep an index for removed items; Basically I wanted an ordered slice where position mattered even after delete

type ListSlice struct {
  sortedArray []int
  deletedIndex map[int]bool
}
func lenSlice(m ListSlice)int{
    return len(m.sortedArray)
}
func deleteSliceElem(index int,m ListSlice){
    m.deletedIndex[index]=true
}
func getSliceElem(m ListSlice,i int)(int,bool){
    _,deleted :=m.deletedIndex[i]
    return m.sortedArray[i],deleted
}
for i := 0; i < lenSlice(sortedArray); i++ {
        
        k,deleted := getSliceElem(sortedArray,i)
        if deleted {continue}
        ....
        deleteSliceElem(i,sortedArray)

}

m := ListSlice{sortedArray: []int{5, 4, 3},deletedIndex: make(map[int]bool) }
...
Alex Punnen
  • 5,287
  • 3
  • 59
  • 71
-4

here is the playground example with pointers in it. https://play.golang.org/p/uNpTKeCt0sH

package main

import (
    "fmt"
)

type t struct {
    a int
    b string
}

func (tt *t) String() string{
    return fmt.Sprintf("[%d %s]", tt.a, tt.b)
}

func remove(slice []*t, i int) []*t {
  copy(slice[i:], slice[i+1:])
  return slice[:len(slice)-1]
}

func main() {
    a := []*t{&t{1, "a"}, &t{2, "b"}, &t{3, "c"}, &t{4, "d"}, &t{5, "e"}, &t{6, "f"}}
    k := a[3]
    a = remove(a, 3)
    fmt.Printf("%v  ||  %v", a, k)
}