Question

How to Delete an Element from a Slice in Go

goslice

Question

I want to delete an element from a slice in Go based on its position.

Here is my current code:

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

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

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

This code is intended to remove one element from the slice, but it does not behave correctly. What is the proper way to delete an element from a slice in Go?

Short Answer

By the end of this page, you will understand how slice deletion works in Go, why slices cannot remove elements directly, and how to create a new slice without the unwanted item using idiomatic Go code such as append(slice[:i], slice[i+1:]...). You will also learn how to handle index validation and avoid common off-by-one mistakes.

Concept

In Go, a slice is a flexible view over an underlying array. Unlike some other languages, slices do not have a built-in delete operation for removing an element by index. Instead, you create a new slice that skips the element you do not want.

The most common and idiomatic approach is:

arr = append(arr[:pos], arr[pos+1:]...)

This works by combining:

  • arr[:pos] → everything before the element
  • arr[pos+1:] → everything after the element
  • append(...) → joins those two parts together

Why this matters:

  • Slices are used everywhere in Go for lists of data.
  • Real programs often need to remove items from memory, user input, API results, or filtered data.
  • Understanding slice deletion helps you write simpler and safer code.

A key point: deleting from a slice does not shrink an array in place. It creates a new slice value, often reusing the same underlying array.

You should also validate the index before deleting, because using an invalid position will cause a runtime panic.

Mental Model

Think of a slice like a train made of connected carriages.

If you want to remove one carriage in the middle, you do not "delete" it magically. Instead, you reconnect:

  • the carriages before it
  • to the carriages after it

So if the slice is:

[10, 20, 30, 40, 50]

and you remove index 2 (30), you reconnect:

  • [10, 20]
  • with [40, 50]

resulting in:

[10, 20, 40, 50]

That is exactly what append(arr[:pos], arr[pos+1:]...) does.

Take Quiz

Syntax and Examples

Core syntax

slice = append(slice[:index], slice[index+1:]...)

Example: remove an element by index

package main

import "fmt"

func main() {
    arr := []int{10, 20, 30, 40, 50}
    pos := 2

    if pos < 0 || pos >= len(arr) {
        fmt.Println("Invalid position")
        return
    }

    arr = append(arr[:pos], arr[pos+1:]...)
    fmt.Println(arr)
}

Output:

[10 20 40 50]

What this does

  • arr[:pos] gives all elements before pos
  • arr[pos+1:] gives all elements after pos
  • ... expands the second slice into individual elements for append

Example with user input

package main

import "fmt"

func main() {
    arr := []int{1, 2, 3, 4, 5}
    var pos int

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

    if pos < 0 || pos >= len(arr) {
        fmt.Println("Invalid position")
        return
    }

    arr = append(arr[:pos], arr[pos+1:]...)
    fmt.Println("Updated slice:", arr)
}

This is shorter, clearer, and less error-prone than manually copying elements with two counters.

Step by Step Execution

Consider this code:

arr := []int{10, 20, 30, 40, 50}
pos := 2
arr = append(arr[:pos], arr[pos+1:]...)
fmt.Println(arr)

Step 1: Original slice

[10, 20, 30, 40, 50]

Indexes are:

IndexValue
010
120
230
340
450

Step 2: Take elements before pos

arr[:2]

Result:

[10, 20]

Step 3: Take elements after pos

arr[3:]

Result:

[40, 50]

Step 4: Append the second part to the first

append([]int{10, 20}, 40, 50)

Result:

[10, 20, 40, 50]

Step 5: Store the result back

arr = [10, 20, 40, 50]

Final output

[10 20 40 50]

The original element at index 2 is skipped, so it is effectively removed.

Real World Use Cases

Deleting an element from a slice is common in many Go programs.

Common scenarios

  • Removing a completed task from a todo list
  • Deleting a user-selected item from a CLI menu
  • Dropping invalid records from parsed data
  • Removing an item from an in-memory cache
  • Excluding a failed job from a processing queue

Example: remove a product from a cart

cart := []string{"book", "pen", "bag"}
removeIndex := 1
cart = append(cart[:removeIndex], cart[removeIndex+1:]...)
fmt.Println(cart)

Output:

[book bag]

Example: remove a bad value after validation

scores := []int{90, -1, 75, 88}
badIndex := 1
scores = append(scores[:badIndex], scores[badIndex+1:]...)
fmt.Println(scores)

This pattern is useful whenever your program keeps data in memory and needs to exclude one entry.

Take Quiz

Real Codebase Usage

In real projects, developers usually wrap slice deletion in a helper function and combine it with validation.

Common pattern: helper function

func removeAt(slice []int, index int) []int {
    if index < 0 || index >= len(slice) {
        return slice
    }
    return append(slice[:index], slice[index+1:]...)
}

This makes the code reusable and safer.

Guard clause pattern

Developers often check invalid conditions early:

if pos < 0 || pos >= len(arr) {
    return
}

This avoids deeply nested logic and prevents runtime errors.

Filtering instead of deleting one index

Sometimes developers do not know the index ahead of time. In that case, they build a new slice using a condition:

result := arr[:0]
for _, v := range arr {
    if v != 30 {
        result = append(result, v)
    }
}
arr = result

This is common when removing values based on rules rather than position.

Error handling with user input

In command-line tools or APIs, index values often come from users or requests. Real code should validate input before slicing to avoid panics.

Common Mistakes

1. Not checking the index range

If pos is invalid, the program panics.

Broken code:

arr = append(arr[:pos], arr[pos+1:]...)

Safer version:

if pos < 0 || pos >= len(arr) {
    fmt.Println("Invalid position")
    return
}
arr = append(arr[:pos], arr[pos+1:]...)

2. Forgetting the ...

Broken code:

arr = append(arr[:pos], arr[pos+1:])

Why it fails:

  • append expects values to append
  • arr[pos+1:] is a slice
  • ... expands the slice into values

Correct code:

arr = append(arr[:pos], arr[pos+1:]...)

3. Mixing indexes while manually copying

Your original code uses both i and k, which makes the logic harder to follow and easier to break.

Broken style:

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

This can lead to incorrect copying or skipped values.

4. Assuming slices behave like dynamic arrays with built-in deletion

Go slices are flexible, but deletion is done by reslicing and appending, not by calling something like delete(slice, index).

5. Forgetting that order matters

The standard append(slice[:i], slice[i+1:]...) keeps order. If order does not matter, some programs use a faster approach by replacing the target with the last element:

arr[pos] = arr[len(arr)-1]
arr = arr[:len(arr)-1]

But this changes the order of elements.

Comparisons

Slice deletion approaches

ApproachKeeps order?Easy to read?Typical use
append(slice[:i], slice[i+1:]...)YesYesStandard deletion by index
Manual copy into new sliceYesNoRarely needed for beginners
Replace with last element, then shortenNoYesFaster removal when order does not matter

Standard removal vs swap-with-last

Standard removal

arr = append(arr[:pos], arr[pos+1:]...)
  • Preserves original order
  • Most common solution
  • Best default choice

Swap with last

arr[pos] = arr[len(arr)-1]
arr = arr[:len(arr)-1]
  • Faster in some cases
  • Does not preserve order
  • Useful in performance-sensitive code

Slice vs array in Go

FeatureSliceArray
Flexible length viewYesNo
Commonly used in GoYesLess often
Easy reslicingYesNo
Can use appendYesNo

For most Go programs, you will work with slices rather than arrays.

Take Quiz

Cheat Sheet

Delete by index

slice = append(slice[:i], slice[i+1:]...)

Safe version

if i >= 0 && i < len(slice) {
    slice = append(slice[:i], slice[i+1:]...)
}

Remove last element

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

Remove first element

slice = slice[1:]

Fast removal when order does not matter

slice[i] = slice[len(slice)-1]
slice = slice[:len(slice)-1]

Rules to remember

  • Always validate the index
  • Use ... when appending a slice into another slice
  • append(slice[:i], slice[i+1:]...) preserves order
  • Slices do not have a built-in delete by index
  • Removing an item changes the slice length

Common edge cases

  • i < 0 → invalid
  • i >= len(slice) → invalid
  • empty slice → cannot remove anything
  • removing the last item works with slice[:len(slice)-1] or the standard pattern

FAQ

How do I remove an element from a slice in Go?

Use:

slice = append(slice[:i], slice[i+1:]...)

This removes the element at index i.

Why is there no delete for slices in Go?

Because slices are views over arrays. Go expects you to build a new slice layout using slicing and append.

Do I need to create a new slice manually?

Usually no. The idiomatic append(slice[:i], slice[i+1:]...) is enough.

What happens if the index is out of range?

Your program will panic at runtime. Always check that i >= 0 && i < len(slice).

Does deleting from a slice preserve order?

Yes, the standard append(slice[:i], slice[i+1:]...) approach preserves the order of the remaining elements.

Is there a faster way if I do not care about order?

Yes:

slice[i] = slice[len(slice)-1]
slice = slice[:len(slice)-1]

This is useful when performance matters more than element order.

Take Quiz

Mini Project

Description

Build a small Go program that removes an item from a list of numbers based on a position entered by the user. This project demonstrates safe slice deletion, index validation, and printing updated results. It is a practical version of what many command-line tools do when modifying in-memory data.

Goal

Create a Go program that reads a position, removes that element from a slice safely, and prints the updated slice.

Requirements

  • Start with a slice containing at least five integers.
  • Read the position to delete from user input.
  • Validate that the position is within range.
  • Remove the element using idiomatic slice syntax.
  • Print the updated slice after deletion.
Take Quiz

Keep learning

Related questions

View more