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.
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.
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.
append
doesn't create a new backing array if it doesn't need to, so why should removing create a new slice? go.dev/play/p/8V9rbjrDkt5
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.
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]
}
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]:
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.
s[i] = s[0]
, then return an array with only the last n-1 elements. return s[1:]
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.
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]
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] }
append
can modify the backing array, so why can't remove? go.dev/play/p/9eQStgiqYYK
s2 = append(s2, 2)
and if you omit this step, the backing array s2
remains unchanged. Compare with go.dev/play/p/7EubNjwOFuD
Using Delete
from the slices
package (experimental as of Go 1.18, planned to be stable in Go 1.19):
slice := []int{1, 2, 3, 4}
slice = slices.Delete(slice, 1, 2)
fmt.Println(slice) // [1 3 4]
slices.Delete(s, i, j)
removes the elements s[i:j] from s. Note two things:
Delete modifies the contents of the original slice
Still, you need to reassign slice because otherwise it would have the wrong length
append(slice[:s], slice[s+1:]...)
. More info: cs.opensource.google/go/x/exp/+/0b5c67f0:slices/slices.go;l=156
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
}
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
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 its not there yet
if i != len(s)-1 {
s[i] = s[len(s)-1]
}
// drop the last element
return s[:len(s)-1]
}
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]
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"
var value reflect.Value = reflect.ValueOf(array).Elem(); value.Set(reflect.AppendSlice(value.Slice(0, index), value.Slice(index+1, value.Len())))
.
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
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
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] }
If it is not necessary to preserve the order, we can simply move the last element to the gap. func remove(slice []int, i int) []int { slice[i] = slice[len(slice)-1] return slice[:len(slice)-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.
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")
}
Delete
a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]
Delete without preserving order
a[i] = a[len(a)-1]
a = a[:len(a)-1]
NOTE If the type of the element is a pointer or a struct with pointer fields, which need to be garbage collected, the above implementations of Cut and Delete have a potential memory leak problem: some elements with values are still referenced by slice a and thus can not be collected. The following code can fix this problem:
Delete
copy(a[i:], a[i+1:])
a[len(a)-1] = nil // or the zero value of T
a = a[:len(a)-1]
Delete without preserving order
a[i] = a[len(a)-1]
a[len(a)-1] = nil
a = a[:len(a)-1]
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.
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)
}
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) }
...
Success story sharing
s[i] = s[len(s)-1]
definitely copies the last element to the element at indexi
. Then,return s[:len(s)-1]
returns the slice without the last element. Two statements there.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 removenil
before slicing so you don't have pointers in the underlying array. This answer explains why very well. In short: after moving the last element at the deleted element's location, zero the last element before slicing.