Как удалить элемент из слайса в Голанге
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)
}