go从已知列表中查找字符串

2016-05-01 LEo 更多博文 » 博客 » GitHub »

原文链接 http://reborncodinglife.com/2016/05/01/find-a-string-tips/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


最近在开发中遇到一个需求,需要查找某个给定的字符串是否属于有效字符串。例如以下字符串都是有效字符串:

"key1" "key2" "key3" "key4" "key5" "key6"

若查找的字符串是key1,存在key1,所以key1是有效字符串,若查找的字符串是key0,不存在key0,所以key0是无效字符串。

我通过4种方式实现,分别如下:

方式一:使用map

将有效的字符串定义成map的key,value都是true,如下:

var validKeyMap = map[string]bool{
    "key1": true,
    "key2": true,
    "key3": true,
    "key4": true,
    "key5": true,
    "key6": true,
}

使用map的特性查找某个键是的值,如下:

key := "key1"
if validKeyMap[key] {
    fmt.Println("found via map")
} else {
    fmt.Println("not found via map")
}

方式二:遍历列表

将有效字符串定义成一个切片,如下:

var validKeyList = []string{
    "key1",
    "key2",
    "key3",
    "key4",
    "key5",
    "key6",
}

通过遍历切片查找特定字符串,如下:

var found bool
key := "key1"
for index := range validKeyList {
    if validKeyList[index] == key {
        found = true
        break
    }
}

if found {
    fmt.Println("found via list")
} else {
    fmt.Println("not found via list")
}

方式三:使用sort库

借助sort库,先将切片排序,然后通过调用SearchStrings查找目标字符串:

sort.Strings(validKeyList)
index := sort.SearchStrings(validKeyList, key)
found = (index < len(validKeyList) && validKeyList[index] == key)

if found {
    fmt.Println("found via sort lib")
} else {
    fmt.Println("not found via sort lib")
}

方式四:使用switch

使用switch语句的特性,遍历所有字符串查找,如下:

key := "key1"

switch key {

    case "key1":
        fallthrough

    case "key2":
        fallthrough

    case "key3":
        fallthrough

    case "key4":
        fallthrough

    case "key5":
        fallthrough

    case "key6":
        fmt.Println("found via switch")
    default:
        fmt.Println("not found via switch")
    }

总结

方式一由于定义一个map,内存相对其他方式有一定的开销,但是该方式查找效率最高,时间复杂度为常数O(1),所以一般推荐使用;

方式二由于需要遍历所有字符串,时间复杂度是O(N),N是切片的长度,随着长度增大,查找时间越长,但是相比方式四,代码少了很多,谨记代码越少出错概率越小,要想软件没有bug,唯一的方法就是不写代码;

方式三通过使用go标准库sort,将切片先排序后,使用二分法查找目标字符串,算法复杂读相对方式二和方式四较好,为O(logN),N为切片长度,可读性较好,比方式二更优,但会改变原切片元素顺序,若对元素顺序敏感慎用;

方式四借助switch语句特性,时间复杂度不定。若查找的字符串是key1,则时间复杂度O(1),但是若查找的字符串是最后一个字符串时,时间复杂度和方式二一样,都是O(N),N表示字符串个数,但是该方式没有没有使用任何数据结构,如果对内存开销要求高,可以推荐使用。

附上完整代码

package main

import (
    "fmt"
    "sort"
)

func main() {

    var validKeyList = []string{
        "key1",
        "key2",
        "key3",
        "key4",
        "key5",
        "key6",
    }

    var validKeyMap = map[string]bool{
        "key1": true,
        "key2": true,
        "key3": true,
        "key4": true,
        "key5": true,
        "key6": true,
    }

    key := "key1"
    if validKeyMap[key] {
        fmt.Println("found via map")
    } else {
        fmt.Println("not found via map")
    }

    var found bool
    for index := range validKeyList {

        if validKeyList[index] == key {
            found = true
            break
        }

    }

    if found {
        fmt.Println("found via list")
    } else {
        fmt.Println("not found via list")
    }

    sort.Strings(validKeyList)
    index := sort.SearchStrings(validKeyList, key)
    found = (index < len(validKeyList) && validKeyList[index] == key)

    if found {
        fmt.Println("found via sort lib")
    } else {
        fmt.Println("not found via sort lib")
    }

    switch key {

    case "key1":
        fallthrough

    case "key2":
        fallthrough

    case "key3":
        fallthrough

    case "key4":
        fallthrough

    case "key5":
        fallthrough

    case "key6":
        fmt.Println("found via switch")
    default:
        fmt.Println("not found via switch")
    }
}

输出

found via map
found via list
found via sort lib
found via switch