英文:
Create a new slice given a previous one, without a given value
问题
我有一个字符串切片。我需要做的是在不知道索引的情况下从切片中删除一个值。我认为这是最简单的方法:
// 返回一个不包含指定字符串的切片
func newSliceWithout(s []string, without string) []string {
l := []string{}
for _, elem := range s {
if elem != without {
l = append(l, elem)
}
}
return l
}
然而,当进行基准测试时,我得到了相当高的值(如预期),所以我想知道是否有更快/更高效的方法来做到这一点?
英文:
I have a slice of strings. What I need to accomplish is to remove one value from the slice, without knowing the index. I thought this would be the easiest way to do it:
// Return a slice that is the original without the given string
func newSliceWithout(s []string, without string) []string {
l := []string{}
for _, elem := range s {
if elem != without {
l = append(l, elem)
}
}
return l
}
However, when performing benchmarks I get pretty high values (as expected), so I'm wondering if there's a faster / more efficient way to do it?
答案1
得分: 3
在一步中分配一个大的返回切片(由输入切片估计大小),不使用append()
,而是分配给单个元素:
func newSliceWithout(s []string, without string) []string {
l, i := make([]string, len(s)), 0
for _, elem := range s {
if elem != without {
l[i] = elem
i++
}
}
return l[:i]
}
测试代码:
x := newSliceWithout([]string{"a", "b", "a", "c"}, "a")
fmt.Println(x)
输出结果(在Go Playground上尝试):
[b c]
基准测试
func BenchmarkNewSliceWithoutOrig(b *testing.B) {
for n := 0; n < b.N; n++ {
newSliceWithoutOrig([]string{"a", "b", "a", "c"}, "a")
}
}
func BenchmarkNewSliceWithout(b *testing.B) {
for n := 0; n < b.N; n++ {
newSliceWithout([]string{"a", "b", "a", "c"}, "a")
}
}
结果:
BenchmarkNewSliceWithoutOrig-8 7416729 139.0 ns/op 48 B/op 2 allocs/op
BenchmarkNewSliceWithout-8 13280971 103.4 ns/op 64 B/op 1 allocs/op
如果我们使用一个更大的切片:
var s = []string{"a", "b", "x", "y", "z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "c"}
然后基准测试结果为:
BenchmarkNewSliceWithoutOrig-8 2253637 566.8 ns/op 496 B/op 5 allocs/op
BenchmarkNewSliceWithout-8 5160316 224.3 ns/op 256 B/op 1 allocs/op
英文:
Allocate a big return slice in one step (estimated by the input slice), and don't use append()
but assign to individual elements:
func newSliceWithout(s []string, without string) []string {
l, i := make([]string, len(s)), 0
for _, elem := range s {
if elem != without {
l[i] = elem
i++
}
}
return l[:i]
}
Testing it:
x := newSliceWithout([]string{"a", "b", "a", "c"}, "a")
fmt.Println(x)
which outputs (try it on the Go Playground):
[b c]
Benchmarks
func BenchmarkNewSliceWithoutOrig(b *testing.B) {
for n := 0; n < b.N; n++ {
newSliceWithoutOrig([]string{"a", "b", "a", "c"}, "a")
}
}
func BenchmarkNewSliceWithout(b *testing.B) {
for n := 0; n < b.N; n++ {
newSliceWithout([]string{"a", "b", "a", "c"}, "a")
}
}
Result:
BenchmarkNewSliceWithoutOrig-8 7416729 139.0 ns/op 48 B/op 2 allocs/op
BenchmarkNewSliceWithout-8 13280971 103.4 ns/op 64 B/op 1 allocs/op
If we use a bigger slice:
var s = []string{"a", "b", "x", "y", "z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "c"}
Then benchmark results:
BenchmarkNewSliceWithoutOrig-8 2253637 566.8 ns/op 496 B/op 5 allocs/op
BenchmarkNewSliceWithout-8 5160316 224.3 ns/op 256 B/op 1 allocs/op
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论