创建一个新的切片,给定一个先前的切片,但不包含给定的值。

huangapple go评论76阅读模式
英文:

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{&quot;a&quot;, &quot;b&quot;, &quot;a&quot;, &quot;c&quot;}, &quot;a&quot;)
fmt.Println(x)

which outputs (try it on the Go Playground):

[b c]

Benchmarks

func BenchmarkNewSliceWithoutOrig(b *testing.B) {
	for n := 0; n &lt; b.N; n++ {
		newSliceWithoutOrig([]string{&quot;a&quot;, &quot;b&quot;, &quot;a&quot;, &quot;c&quot;}, &quot;a&quot;)
	}
}

func BenchmarkNewSliceWithout(b *testing.B) {
	for n := 0; n &lt; b.N; n++ {
		newSliceWithout([]string{&quot;a&quot;, &quot;b&quot;, &quot;a&quot;, &quot;c&quot;}, &quot;a&quot;)

	}
}

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{&quot;a&quot;, &quot;b&quot;, &quot;x&quot;, &quot;y&quot;, &quot;z&quot;, &quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;, &quot;6&quot;, &quot;7&quot;, &quot;8&quot;, &quot;9&quot;, &quot;a&quot;, &quot;c&quot;}

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

huangapple
  • 本文由 发表于 2021年5月23日 21:38:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/67660392.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定