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])
}
我正在使用此命令从Slice中删除一个元素,但它不起作用,请建议。
答案 0 :(得分:71)
订单重要
如果要保持数组的有序,则必须将删除索引右侧的所有元素向左移动一个。希望这可以在Golang中轻松完成:
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.06ns。我怀疑在内部,只改变切片的长度,而不修改它。
修改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的负值或指数将导致Go恐慌。切片和数组被0索引,删除数组的第n个元素意味着提供输入 n-1 。要删除第一个元素,请调用删除(s,0),删除第二个元素,调用删除(s,1),依此类推。
答案 1 :(得分:19)
次要点(代码高尔夫),但在订单无关紧要的情况下,您不需要交换值。只需使用最后一个位置的副本覆盖要删除的数组位置,然后返回截断的数组。
func remove(s []int, i int) []int {
s[i] = s[len(s)-1]
return s[:len(s)-1]
}
同样的结果。
答案 2 :(得分:12)
这是您切片以惯用方式 删除的方式。您不需要构建附加在附件中的函数。 在这里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]
答案 3 :(得分:10)
从Slice中删除一个元素(这称为“重新切片”):
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]
n := RemoveIndex(all, 5)
fmt.Println(n) //[0 1 2 3 4 6 7 8 9]
}
答案 4 :(得分:2)
最好的方法是使用append函数:
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)
}
答案 5 :(得分:2)
找到一种here而无需重新定位的方式。
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]
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]
答案 6 :(得分:1)
除非您关注内容,否则无需检查每个元素,您可以使用切片追加。尝试一下
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 :(得分:1)
摘自The Go Programming Language书
要从切片中间删除元素,请保留顺序 剩余元素中的所有元素,请使用“复制”滑动编号较高的元素 元素向下缩小以填补空白:
func remove(slice []int, i int) []int { copy(slice[i:], slice[i+1:]) return slice[:len(slice)-1] }
答案 8 :(得分:1)
也许您可以尝试这种方法:
// 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"
答案 9 :(得分:1)
看到这个有点奇怪,但是这里的大多数答案都是危险的,掩盖了他们实际所做的事情。查看最初提出的有关从切片中删除项目的问题,正在制作切片的副本,然后将其填充。这样可以确保在将切片传递给程序时不会引入细微的错误。
这是一些代码,用于比较用户在此主题中的答案和原始帖子。这是一个go playground,用于处理此代码。
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
也被修改了。 Effective go对此进行了更详细的介绍。
下面的示例我不会涉及,但出于我们的目的,它做了同样的事情。只是说明使用副本没有什么不同。
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
的更改,删除索引并为其分配索引的操作也不会导致更改!太棒了!
尽管此代码有点冗长,所以上面的内容可以更改为
。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]
}
几乎与原始的remove index解决方案相同,但是我们在返回之前制作了一个要附加到的新切片。
答案 10 :(得分:1)
我采用以下方法删除切片中的项目。这有助于他人阅读。而且也是一成不变的。
func remove(items []string, item string) []string {
newitems := []string{}
for _, i := range items {
if i != item {
newitems = append(newitems, i)
}
}
return newitems
}
答案 11 :(得分:1)
也许此代码会有所帮助。
它将删除具有给定索引的项目。
获取数组,删除要删除的索引并返回一个新数组,就像添加函数一样。
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]
}
在这里您可以使用以下代码:https://play.golang.org/p/aX1Qj40uTVs
答案 12 :(得分:0)
要从切片中间删除元素,请保留顺序 剩余元素中的所有元素,请使用copy滑动编号较高的元素 元素向下缩小以填补空白:
func remove(slice []int, i int) []int { copy(slice[i:], slice[i+1:]) return slice[:len(slice)-1] }
如果没有必要保留顺序,我们可以简单地将最后一个元素移到空白处。
func remove(slice []int, i int) []int { slice[i] = slice[len(slice)-1] return slice[:len(slice)-1] }
答案 13 :(得分:0)
T. Claverie 目前投票最多的答案是正确的,但我发现如果仅在需要时才执行交换,则算法更清晰,即除了切片的最后一个元素之外的所有元素。这可以通过一个简单的 if 守卫来实现。
顺序不重要/不执行边界检查
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]
}
答案 14 :(得分:-1)
这是带有指针的游乐场示例。 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)
}
答案 15 :(得分:-2)
因为 Slice 是由一个数组支持的,而且你无法从数组中删除一个元素而不是重新调整内存;而且我不想做那些丑陋的代码;这是一个伪代码,用于保留已删除项目的索引;基本上我想要一个有序的切片,即使在删除之后位置也很重要
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) }
...