In Golang, we deal with slices very often, they are the arrays of other programming languages, and they are used lot in Golang, so one of the tasks we would need, is to delete an element of a slice, and that element might require us to rearrange the slice, or sometimes we dont care, we just want to delete that element, and keep the rest of the slice. This tutorial will explain to you the exact steps you would need to take in order to delete any element of a slice fairly easily.
Delete first element from slice
To delete first element of a slice, we have a simple step, we truncate all elements of the slice, from the index 1
, to the end. in this way we delete element of index 0
package main
import ("fmt")
func main() {
theSlice := []int{1, 2, 3, 4, 5}
fmt.Println(deleteFirstElement(theSlice))
}
func deleteFirstElement(slice []int) []int {
slice = slice[1:len(slice)] // [2 3 4 5]
return slice
}
We truncate the first element, by starting from index 1, all the way to the end
This takes a constant time to truncate that first element. O(1)
Delete first n elements from slice
If we have a task to delete a number of elements n, in a slice we would do the thing, but with defining from where we start our deletion.
We would of course need to make sure, the value we are providing as n, is within an acceptable range. feel free to manipulate that, because if you don't check, you might run to a panic situation, if you try to delete more elements than what the slice does have.
package main
import ("fmt")
func main() {
theSlice := []int{1, 2, 3, 4, 5}
fmt.Println(deleteNElementsFromBeginning(theSlice, 2))
}
func deleteNElementsFromBeginning(slice []int, n int) []int {
if len(slice)-n < 1 {
return slice
}
slice = slice[n:len(slice)] // [3,4,5]
return slice
}
This takes a constant time to truncate that n element. O(1)
Delete last element from slice
Deleting the last element of the slice, is a similar operation to deleting from the end, except we change the range of the slice we want so
package main
import ("fmt")
func main() {
theSlice := []int{1, 2, 3, 4, 5}
fmt.Println(deleteLastElement(theSlice))
}
func deleteLastElement(slice []int) []int {
slice = slice[:len(slice)-1] //[1 2 3 4]
return slice
}
This takes a constant time to truncate that last element. O(1)
Delete last n elements from slice
Again we might need to delete n elements from a slice, we would need to do the same operation, but we do a checking whether that keeps our manipulation in the range or not, in case a slice of 10 elements and you want to delete 20 elements, a panic will be thrown, that's way I would return the slice as is. without manipulation, feel free to change that for your needs
package main
import ("fmt")
func main() {
theSlice := []int{1, 2, 3, 4, 5}
fmt.Println(deleteNElementsFromEnd(theSlice, 2))
}
func deleteNElementsFromEnd(slice []int, n int) []int {
if len(slice)-n < 1 {
return slice
}
slice = slice[:len(slice)-n] //[1 2 3]
return slice
}
Delete random elements from slice
To delete a random element from a slice, we first need to generate a random number, between the length of the slice, and 0 as its first element, then we use that as the element we want to delete. then we shift the elements of the slice in the same order, by re-appending them to the slice, starting from the next position from that index
package main
import (
"math/rand"
"fmt"
)
func main() {
theSlice := []int{1, 2, 3, 4, 5}
fmt.Println(removeElementRandomly(theSlice))
}
func removeElementRandomly(slice []int) []int {
index := rand.Int31n(int32(len(slice) -1)) // generate a random integer in the range 0 <= n < length of slice - 1
return append(slice[:index], slice[index+1:]...)
}
- We generate a random integer, that is the index we will delete, the index range is from 0 to the last element of the slice.
- We shift all elements of the slice who are after that element
This takes a linear time to delete the random element. O(n) because we are shifting all the elements after it. and keeping the order
Delete element of a slice based on its position (index number)
We can delete elements from a slice, by the index, but we can do that, in two different ways.
Without keeping the order
So given we have a slice, and we try to get ride of an element, we know its index, we what we can do, is to assign the last element of the slice, and duplicate it, in the same position, of the element we want to delete, then we basically would have the same slice, except this element, being stamped by the last element of the slice. Then we simply truncate the slice, and take all the slice except the last element. let me show you
package main
import ("fmt")
func main() {
theSlice := []int{1, 2, 3, 4, 5}
fmt.Println(remvoesAtIndex(theSlice, 2))
}
func remvoesAtIndex(slice []int, index int) []int {
// we copy stamp the element at index 2, with the last element of the slice
slice[index] = slice[len(slice)-1] //[1 2 5 4 5]
// by now our slice is of the same size, except it has the value of of the element in two positions
// the last position and the position we deleted. now all we need to do is to truncate the last element from the slice
slice = slice[:len(slice)-1] // [1 2 5 4]
return slice
}
- We stamp the element last element, in the element we want to delete
- We then truncate the slice, and take all elements except the last one
The time complexity of this approach is O(1)
time. so constant time.
Keeping the slice order
If maintaining the order is important to us, we have to do a different approach. we need to shift, by making a copy of all elements of the slice, that after the element we want to delete, by which gain, the last element will be a duplicated one, as we wont touch to it.
Then we just truncate the slice.
package main
import ("fmt")
func main() {
theSlice := []int{1, 2, 3, 4, 5}
fmt.Println(remvoesAtIndexKeepOrder(theSlice, 2))// we get rid of element at index 2
}
func remvoesAtIndexKeepOrder(slice []int, index int) []int {
//[1 2 3 4 5]
// copy the elements who come after the element we want to delete
copy(slice[index:], slice[index+1:]) // [1 2 4 5 5]
// truncate the slice by taking all the elements except the last element
slice = slice[:len(slice)-1] // [1 2 4 5]
return slice
}
- We copy (shift) the elements of the slice who come after the one we want to delete, starting from the one we want to delete, so last element will be a duplicate
- We truncate the last element
The time complexity of this approach is O(n)
time. because of the copy step. Linear time.
Deleting n elements from the slice, starting from an index
as we can shift or copy elements of a slice, we can delete n elements from the slice by using this last method, where keep the order, we simply would need the index our starting point, and the number of elements we want to delete
package main
import ("fmt")
func main() {
theSlice := []int{1, 2, 3, 4, 5}
fmt.Println(remvoesAtIndexSlowNElements(theSlice, 2,2))// we get rid of element at index 2
}
func remvoesAtIndexSlowNElements(slice []int, index int, n int) []int {
// we check if the range between index and n, dosent exceed the length of the slice, otherwise we just return the slice as is
if len(slice)-index < n {
return slice
}
//[1 2 3 4 5]
// copy the elements who come after the element we want to delete
copy(slice[index:], slice[index+n:]) // [1 2 5 4 5]
// truncate the slice by taking all the elements except the last element
slice = slice[:len(slice)-n] //
return slice
}
- We first check for the n wether its in the range of the slice.
- We then copy all the elements after index + n
- Then we truncate the n number of elements.
The time complexity of this approach is O(n)
time. because of the copy step. Linear time.
Conclusion
Slices manipulation, is one critical thing to learn, and this tutorial should clarify any deletion operation you need for your next project. Use each technique for its purpose with maximum performance.