Golang String Array Contains Performance

在 Golang 裏頭對字串陣列檢查特定字串是否有存在,並回傳 index

比較 reflect, wgo package, 以及 slices

結論是,code要簡潔且效能快,用 slices

// contains.go
package main

import (
    "reflect"

    "github.com/wxnacy/wgo/arrays"

    "slices"
)

func Contains(array interface{}, val interface{}) (index int) {
    index = -1
    switch reflect.TypeOf(array).Kind() {
    case reflect.Slice:
        {
            s := reflect.ValueOf(array)
            for i := 0; i < s.Len(); i++ {
                if reflect.DeepEqual(val, s.Index(i).Interface()) {
                    index = i
                    return
                }
            }
        }
    }
    return
}

func StringsContains(array []string, val string) (index int) {
    index = -1
    for i := 0; i < len(array); i++ {
        if array[i] == val {
            index = i
            return
        }
    }
    return
}

func SliceContains(array []string, val string) (index int) {
    i := slices.Index(array, val) // Use .Index() here, because other .Contains() methods return index, not boolean
    return i
}

func WgoContains(array []string, val string) (index int) {
    i := arrays.Contains(array, val)
    return i
}

func WgoSwitchContains(array interface{}, val interface{}) (index int) {
    var i int
    switch val.(type) {
    case string:
        var arrtmp []string
        s := reflect.ValueOf(array)
        for i := 0; i < s.Len(); i++ {
            arrtmp = append(arrtmp, s.Index(i).Interface().(string))
        }
        i = arrays.StringsContains(arrtmp, val.(string))
    }

    return i
}

func WgoStringsContains(array []string, val string) (index int) {
    i := arrays.StringsContains(array, val)
    return i
}

順便用 unit test 來做測試

package main

import (
    "testing"
)

var sa []string = []string{"q", "w", "e", "r", "t", "a", "b", "c", "d", "f", "g", "h", "i", "j", "x", "y", "z", "1", "2", "3", "4", "5", "6", "7"}
var needle string = "5"

func BenchmarkContains(b *testing.B) {
    b.ResetTimer()
    for n := 0; n < b.N; n++ {
        Contains(sa, needle)
    }
}

func BenchmarkStringsContains(b *testing.B) {
    b.ResetTimer()
    for n := 0; n < b.N; n++ {
        StringsContains(sa, needle)
    }
}

func BenchmarkWgoContains(b *testing.B) {
    b.ResetTimer()
    for n := 0; n < b.N; n++ {
        WgoContains(sa, needle)
    }
}

func BenchmarkWgoStringsContains(b *testing.B) {
    b.ResetTimer()
    for n := 0; n < b.N; n++ {
        WgoStringsContains(sa, needle)
    }
}

func BenchmarkWgSwitchContains(b *testing.B) {
    b.ResetTimer()
    for n := 0; n < b.N; n++ {
        WgoSwitchContains(sa, needle)
    }
}

func BenchmarkSliceContains(b *testing.B) {
    b.ResetTimer()
    for n := 0; n < b.N; n++ {
        SliceContains(sa, needle)
    }
}

結果

> go test -bench .
goos: windows
goarch: amd64
pkg: mytest
cpu: 13th Gen Intel(R) Core(TM) i7-1370P
BenchmarkContains-20                     1420240               777.4 ns/op
BenchmarkStringsContains-20             25506679                55.94 ns/op
BenchmarkWgoContains-20                  1000000              1059 ns/op
BenchmarkWgoStringsContains-20          21460915                48.68 ns/op
BenchmarkWgSwitchContains-20             1205704               918.1 ns/op
BenchmarkSliceContains-20               18048748                62.82 ns/op
PASS