Skip to content

关于比较两个字符串切片的疑惑 #2

@OhYee

Description

@OhYee

@geektutu

关于该部分内容

## Q13 如何判断 2 个字符串切片(slice) 是相等的?
<details>
<summary>答案</summary>
<div>
go 语言中可以使用反射 `reflect.DeepEqual(a, b)` 判断 a、b 两个切片是否相等,但是通常不推荐这么做,使用反射非常影响性能。
通常采用的方式如下,遍历比较切片中的每一个元素(注意处理越界的情况)。
```go
func StringSliceEqualBCE(a, b []string) bool {
if len(a) != len(b) {
return false
}
if (a == nil) != (b == nil) {
return false
}
b = b[:len(a)]
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
```
</div>
</details>

这里我试了一下,貌似 reflect.DeepEqual 的效率实际上是比 for 循环要高的

package main

import (
	"math/rand"
	"reflect"
	"testing"
	"time"
)

var (
	l  = 100000
	l2 = 100
	s1 = generate(l)
	s2 = generate(l)
	s3 = generate(l * 2)
)

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")

func randStringRunes(n int) string {
	rand.Seed(time.Now().UnixNano())
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

func generate(n int) []string {
	s := make([]string, n)
	for i := 0; i < n; i++ {
		s[i] = randStringRunes(l2)
	}
	return s
}

func cmp1(a, b []string) bool {
	return reflect.DeepEqual(a, b)
}

func cmp2(a, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	if (a == nil) != (b == nil) {
		return false
	}
	b = b[:len(a)]
	for i, v := range a {
		if v != b[i] {
			return false
		}
	}
	return true
}

func BenchmarkReflect(b *testing.B) {
	for i := 0; i < b.N; i++ {
		cmp1(s1, s2)
		cmp1(s1, s3)
		cmp1(s1, s1)
	}
}

func BenchmarkFor(b *testing.B) {
	for i := 0; i < b.N; i++ {
		cmp2(s1, s2)
		cmp2(s1, s3)
		cmp2(s1, s1)
	}
}

l = 100000l2=100时,

$ go test -bench=.
goos: linux
goarch: amd64
BenchmarkReflect-4       1235326               856 ns/op
BenchmarkFor-4              2890            354342 ns/op
PASS

l = 100l2=100000时,

$  go test -bench=.
goos: linux
goarch: amd64
BenchmarkReflect-4       1205154               866 ns/op
BenchmarkFor-4           3315399               373 ns/op
PASS

好像只有切片长度很短时,for 循环具有优势,但是优势也并不大

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions