英文:
Idiomatic Splice in Go
问题
我检查了一个现有的答案,但它与我的情况不相似。
我需要根据Compare
函数,在运行时从索引中取出一个元素,并跳出for
循环。
问题:
如果要取出的元素位于0
索引处,index-1
将引发切片越界错误,如果index+1
大于len(elements)
也会出现类似的问题。
问题:如何以最简洁的方式实现上述目标?
for index, element := range elements {
if element.Compare() == true {
elements = append(elements[:index-1], elements[index+1:]...)
break
}
}
尝试
for index, element := range elements {
if element.Compare() == true {
if len(elements) > 1 {
elements = append(elements[:index-1], elements[index+1:]...)
} else if len(elements) == 1 {
delete(elements, 0)
}
break
}
}
尝试2 Playground 有什么改进/建议吗?
思路是从开头复制剩余的元素到索引位置,然后复制后面的任何元素。
var elements = []string {"a", "b", "c", "d"}
fmt.Println(elements)
for index, element := range elements {
if element == "c" {
var temp = elements[:index]
for i := index + 1; i<len(elements); i++ {
temp = append(temp, elements[i])
}
elements = temp
break
}
}
fmt.Println(elements)
英文:
I checked an existing answer but it's not similar to my case.
I need to pluck an element at the index and break out of the for
loop at runtime based on Compare
function.
Issues:
If element to pluck is found at 0
index
, index-1
will throw slice bounds of range error and similarly if index+1
is greater than len(elements)
.
Question: What's the best concise way to achieve the above?
for index, element := range elements {
if element.Compare() == true {
elements = append(elements[:index-1], elements[index+1:]...)
break
}
}
Attempt
for index, element := range elements {
if element.Compare() == true {
if len(elements) > 1 {
elements = append(elements[:index-1], elements[index+1:]...)
} else if len(elements) == 1 {
delete(elements, 0)
}
break
}
}
Attempt 2 Playground any improvements/suggestions?
The idea is to copy the remaining elements from beginning to index and then any elements after.
var elements = []string {"a", "b", "c", "d"}
fmt.Println(elements)
for index, element := range elements {
if element == "c" {
var temp = elements[:index]
for i := index + 1; i<len(elements); i++ {
temp = append(temp, elements[i])
}
elements = temp
break
}
}
fmt.Println(elements)
答案1
得分: 5
在slice表达式中,高索引是不包含的。
这意味着你的示例是有缺陷的,也就是说不需要特殊处理。
正确的切片表达式是:
elements = append(elements[:index], elements[index+1:]...)
如果index
是第一个元素(0
),那么elements[:0]
将是一个空切片。
如果index
是最后一个元素(len-1
),那么elements[index+1:]
也将是一个空切片,因为index+1
将等于切片的长度。所以解决方案很简单:
for index, element := range elements {
if element.Compare() {
elements = append(elements[:index], elements[index+1:]...)
break
}
}
为了在Go Playground上演示,让我们用一个简单的索引检查替换Compare()
方法:
for _, idxToRemove := range []int{0, 2, 4} {
s := []int{0, 1, 2, 3, 4}
for i := range s {
if i == idxToRemove {
s = append(s[:i], s[i+1:]...)
break
}
}
fmt.Println(idxToRemove, ":", s)
}
输出结果(在Go Playground上尝试):
0 : [1 2 3 4]
2 : [0 1 3 4]
4 : [0 1 2 3]
英文:
The high index in a slice expression is exclusive.
This means your example is flawed, and also that no special treatment is required.
The correct slicing expression is:
elements = append(elements[:index], elements[index+1:]...)
If index
is the first element (0
), then elements[:0]
will be an empty slice.
If index
is the last element (len-1
), then elements[index+1:]
will also be an empty slice, as index+1
will be equal to the lenght of the slice. So the solution is simply:
for index, element := range elements {
if element.Compare() {
elements = append(elements[:index], elements[index+1:]...)
break
}
}
To demonstrate it on the Go Playground, let's substitute the Compare()
method with a simple index check:
for _, idxToRemove := range []int{0, 2, 4} {
s := []int{0, 1, 2, 3, 4}
for i := range s {
if i == idxToRemove {
s = append(s[:i], s[i+1:]...)
break
}
}
fmt.Println(idxToRemove, ":", s)
}
Output (try it on the Go Playground):
0 : [1 2 3 4]
2 : [0 1 3 4]
4 : [0 1 2 3]
答案2
得分: 0
如果切片s
已排序且len(s)
较大,则可以使用二分查找来查找x
。例如,
package main
import (
"fmt"
"sort"
)
func pluck(s []string, x string) []string {
i := sort.SearchStrings(s, x)
if i >= 0 && i < len(s) && s[i] == x {
s = append(s[:i], s[i+1:]...)
}
return s
}
func main() {
s := []string{"a", "b", "c", "d"}
fmt.Println(s)
s = pluck(s, "b")
fmt.Println(s)
}
输出:
[a b c d]
[a c d]
如果切片s
的顺序不需要保留,则可以交换元素。例如,
package main
import "fmt"
func pluck(s []string, x string) []string {
for i, v := range s {
if v == x {
s[i] = s[len(s)-1]
s = s[:len(s)-1]
break
}
}
return s
}
func main() {
s := []string{"a", "b", "c", "d"}
fmt.Println(s)
s = pluck(s, "b")
fmt.Println(s)
}
输出:
[a b c d]
[a d c]
否则,可以使用切片s
的切片操作。例如,
package main
import "fmt"
func pluck(s []string, x string) []string {
for i, v := range s {
if v == x {
s = append(s[:i], s[i+1:]...)
break
}
}
return s
}
func main() {
s := []string{"a", "b", "c", "d"}
fmt.Println(s)
s = pluck(s, "b")
fmt.Println(s)
}
输出:
[a b c d]
[a c d]
英文:
If the slice s
is sorted and len(s)
is large, find x
using a binary search. For example,
package main
import (
"fmt"
"sort"
)
func pluck(s []string, x string) []string {
i := sort.SearchStrings(s, x)
if i >= 0 && i < len(s) && s[i] == x {
s = append(s[:i], s[i+1:]...)
}
return s
}
func main() {
s := []string{"a", "b", "c", "d"}
fmt.Println(s)
s = pluck(s, "b")
fmt.Println(s)
}
Output:
[a b c d]
[a c d]
If the order of slice s
does not need to be preserved, switch elements. For example,
package main
import "fmt"
func pluck(s []string, x string) []string {
for i, v := range s {
if v == x {
s[i] = s[len(s)-1]
s = s[:len(s)-1]
break
}
}
return s
}
func main() {
s := []string{"a", "b", "c", "d"}
fmt.Println(s)
s = pluck(s, "b")
fmt.Println(s)
}
Output:
[a b c d]
[a d c]
Otherwise, splice slice s
elements. For example,
package main
import "fmt"
func pluck(s []string, x string) []string {
for i, v := range s {
if v == x {
s = append(s[:i], s[i+1:]...)
break
}
}
return s
}
func main() {
s := []string{"a", "b", "c", "d"}
fmt.Println(s)
s = pluck(s, "b")
fmt.Println(s)
}
Output:
[a b c d]
[a c d]
答案3
得分: 0
我不确定这是否符合习惯用法,但这段代码运行得很好:
package main
import "fmt"
func splice(start, count int, items []string) (ret []string) {
ret = make([]string, len(items)-count)
copy(ret, items[:start])
copy(ret[start:], items[start+count:])
return
}
func main() {
s := []string{"a", "b", "c", "d"}
fmt.Println(s)
s = splice(1, 2, s)
fmt.Println(s)
}
Go Playground: https://play.golang.org/p/UNtdtw77sEQ
英文:
I'm not sure if this is idiomatic, but this works quite well:
package main
import "fmt"
func splice(start, count int, items []string) (ret []string) {
ret = make([]string, len(items)-count)
copy(ret, items[:start])
copy(ret[start:], items[start+count:])
return
}
func main() {
s := []string{"a", "b", "c", "d"}
fmt.Println(s)
s = splice(1, 2, s)
fmt.Println(s)
}
Go Playground: https://play.golang.org/p/UNtdtw77sEQ
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论