Как удалить элемент из слайса в Голанге

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])
}

Я использую эту команду для удаления элемента из слайса, но она не работает, пожалуйста, предложите.

Ответ 1

Заказ имеет значение

Если вы хотите сохранить порядок в вашем массиве, вам нужно сместить все элементы справа от удаляемого индекса на один влево. Надеюсь, это легко сделать на Голанге:

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

Однако это неэффективно, потому что вы можете переместить все элементы, что дорого.

Заказ не важен

Если вас не интересует порядок, у вас есть гораздо более быстрая возможность поменять удаляемый элемент на один в конце слайса, а затем вернуть n-1 первых элементов:

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

При использовании метода пересчета очистка массива из 1 000 000 элементов занимает 224 секунды, а при этом - всего 0,06 нс. Я подозреваю, что внутренне go только изменяет длину среза, не изменяя его.

Редактировать 1

Быстрые заметки на основе комментариев ниже (спасибо им!).

Поскольку цель состоит в том, чтобы удалить элемент, когда порядок не имеет значения, требуется один своп, второй будет потрачен впустую:

func remove(s []int, i int) []int {
    s[i] = s[len(s)-1]
    // We do not need to put s[i] at the end, as it will be discarded anyway
    return s[:len(s)-1]
}

Кроме того, этот ответ не выполняет проверку границ. Ожидается действительный индекс в качестве входных данных. Это означает, что отрицательные значения или индексы, которые больше или равны len (s), приведут к панике. Срезы и массивы с индексами 0, удаление n-го элемента массива подразумевает ввод n-1. Чтобы удалить первый элемент, вызовите remove (s, 0), чтобы удалить второй, вызовите remove (s, 1) и так далее, и так далее.

Ответ 2

Незначительная точка (код гольфа), но в случае, когда порядок не имеет значения, вам не нужно менять значения. Просто перезапишите удаляемую позицию массива с дубликатом последней позиции и затем верните усеченный массив.

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

Тот же результат.

Ответ 3

Удалите один элемент из фрагмента (это называется "повторная нарезка"):

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]
}

Ответ 4

Из книги Язык программирования Go

Удалить элемент из середины среза, сохранив порядок из оставшихся элементов, используйте копию, чтобы скользить с более высоким номером элементов на один, чтобы заполнить пробел:

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

Ответ 5

Это немного странно видеть, но большинство ответов здесь опасны и затушевывают то, что они на самом деле делают. При рассмотрении исходного вопроса, который был задан об удалении элемента из фрагмента, создается копия фрагмента, а затем он заполняется. Это гарантирует, что при передаче фрагментов по вашей программе вы не будете вносить тонких ошибок.

Вот некоторый код, сравнивающий ответы пользователей в этой теме и оригинальном сообщении. Здесь есть игровая площадка, где можно поиграть с этим кодом.

Добавить на основе удаления

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]
}

В приведенном выше примере вы можете видеть, как я создаю фрагмент и заполняю его вручную номерами от 0 до 9. Затем мы удаляем индекс 5 из всех и назначаем его для удаления индекса. Однако, когда мы идем распечатывать все сейчас, мы видим, что оно также было изменено. Это потому, что срезы являются указателями на базовый массив. Запись этого в removeIndex также приводит к изменению all, с той разницей, что all длиннее на один элемент, который более недоступен из removeIndex. Затем мы меняем значение в removeIndex и видим, что all также модифицируется. Эффективный подход подробно расскажет об этом.

В следующем примере я не буду вдаваться, но он делает то же самое для наших целей. И просто иллюстрирует, что использование копии ничем не отличается.

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]
}

Оригинальный ответ на вопросы

Глядя на исходный вопрос, он не изменяет фрагмент, с которого он удаляет элемент. Сделать оригинальный ответ в этой теме лучшим для большинства людей, заходящих на эту страницу.

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]
}

Как вы можете видеть, этот вывод действует так, как большинство людей ожидают и, вероятно, того, чего хочет большинство людей. Модификация originalRemove не вызывает изменений в all, а операция удаления индекса и присвоения его также не вызывает изменений! Fantastic!

Этот код немного длинен, поэтому вышеприведенный код можно изменить на него.

Правильный ответ

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]
}

Почти идентично исходному решению для удаления индекса, однако мы создаем новый фрагмент, к которому нужно добавить, прежде чем вернуться.

Ответ 6

Не нужно проверять каждый элемент, если вы не заботитесь о содержимом, и вы можете использовать добавление среза. попробуйте

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")
}

Ответ 7

Может быть, вы можете попробовать этот метод:

// 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)
    }
}

Использование:

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)

Результат:

0, 1, 2, 4, 5
"0", "1", "2", "3", "5"

Ответ 8

Вот пример игровой площадки с указателями. 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)
}