英文:
In place deletion of Golang slice elements
问题
我想以原地方式从集合中删除元素。考虑以下代码片段:
package main
import "fmt"
type Ints []int
func (xs Ints) Filter() {
for i := 0; i < len(xs); i++ {
if xs[i]%2 == 0 { // 或者其他过滤函数
xs = append(xs[:i], xs[i+1:]...)
}
fmt.Printf("i %+v\n", i)
fmt.Printf("xs %+v\n", xs)
}
}
func main() {
a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
fmt.Printf("初始 a %+v\n", a)
a.Filter()
fmt.Printf("最终 a %+v\n", a)
}
这段代码的令人惊讶的结果是:最终 a [1 3 5 7 9 10 10 10 10 10]
我想知道如何解决这个问题。我相当确定接收者需要是指向 Ints
的指针。但这会使代码变得混乱一些(可能需要在每个地方添加 *xs
并加上括号),但更重要的是它产生了相同的结果。
英文:
I want to delete elements from a collection in an in-place manner.
Consider the following snippet:
package main
import "fmt"
type Ints []int
func (xs Ints) Filter() {
for i := 0; i < len(xs); i++ {
if xs[i]%2 == 0 { // Or some other filtering function
xs = append(xs[:i], xs[i+1:]...)
}
fmt.Printf("i %+v\n", i)
fmt.Printf("xs %+v\n", xs)
}
}
func main() {
a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
fmt.Printf("initial a %+v\n", a)
a.Filter()
fmt.Printf("final a %+v\n", a)
}
http://play.golang.org/p/1nL6Il2Gf1
The surprising result is: final a [1 3 5 7 9 10 10 10 10 10]
I wonder how to do this. I'm pretty sure the receiver needs to be a pointer to Ints
. But that messes up the code somewhat (adding *xs
everywhere possibly with brackets) but more importantly it yields the same result.
答案1
得分: 2
我会通过移动元素、调整切片大小和使用指针来完成。类似这样的代码:
package main
import "fmt"
type Ints []int
func (xs *Ints) Filter() {
filterPos := 0
for i := 0; i < len(*xs); i++ {
if (*xs)[i]%2 == 0 { // 或者其他过滤函数
(*xs)[filterPos] = (*xs)[i]
filterPos++
}
}
(*xs) = (*xs)[:filterPos]
}
func main() {
a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
fmt.Printf("初始 a %+v\n", a)
a.Filter()
fmt.Printf("最终 a %+v\n", a)
}
请注意,这是一个示例代码,用于演示如何通过移动元素、调整切片大小和使用指针来过滤切片。你可以根据自己的需求进行修改和适应。
英文:
I'd do it by moving elements, then resizing the slice, and using a pointer. Something like this:
package main
import "fmt"
type Ints []int
func (xs *Ints) Filter() {
filterPos := 0
for i := 0; i < len(*xs); i++ {
if (*xs)[i]%2 == 0 { // Or some other filtering function
(*xs)[filterPos] = (*xs)[i]
filterPos++
}
}
(*xs) = (*xs)[:filterPos]
}
func main() {
a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
fmt.Printf("initial a %+v\n", a)
a.Filter()
fmt.Printf("final a %+v\n", a)
}
答案2
得分: 1
你必须在这里使用指针。如果你不喜欢在每个地方都添加 *xs,只需使用一个临时变量来执行所有操作,然后将其设置回去。这是代码的链接:http://play.golang.org/p/eAFkV3Lwh6
英文:
You must use pointer here. If you don't like adding *xs every where just use a temp variable to do all operations then set it back. Here is the code http://play.golang.org/p/eAFkV3Lwh6
答案3
得分: 1
你的代码几乎是正确的。
第一个 bug 是在删除元素时需要避免执行 i++
,否则 i++
会跳过下一个未读取的元素。这就是为什么我将其放在 else
子句中的原因。
第二个 bug 是 xs
是 Filter
函数的局部变量,所以如果你改变它所指向的内容(使用 xs = ...
),这不会改变 main
函数中 a
所指向的内容。你可以通过将其声明为指针(像其他人发布的那样使用 *xs
)或者通过返回新的过滤切片来解决这个问题,就像我下面所做的那样。
package main
import "fmt"
type Ints []int
func (xs Ints) Filtered() Ints {
for i := 0; i < len(xs); {
if xs[i]%2 == 0 {
xs = append(xs[:i], xs[i+1:]...)
} else {
i++
}
}
return xs
}
func main() {
a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
b := a.Filtered()
fmt.Println(b)
}
你可以在这里运行代码:http://play.golang.org/p/Nre7w4KQ78
英文:
Your code was almost right.
The first bug is that you need to avoid doing i++
when you're deleting an element, otherwise the i++
skips over the next, unread element. That's why I've put it in the else
clause.
The second bug is that xs
is a local variable of the Filter
function, so if you change what it points to (with xs = ...
) that does not change what a
points to inside main
. You can solve this issue by making it a pointer (*xs
as others have posted) or by returning the new filtered slice, as I've done below.
package main
import "fmt"
type Ints []int
func (xs Ints) Filtered() Ints {
for i := 0; i < len(xs); {
if xs[i]%2 == 0 {
xs = append(xs[:i], xs[i+1:]...)
} else {
i++
}
}
return xs
}
func main() {
a := Ints([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
b := a.Filtered()
fmt.Println(b)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论