为了账号安全,请及时绑定邮箱和手机立即绑定

去比较字符串

去比较字符串

Go
元芳怎么了 2023-04-24 16:18:24
给定两个字符串a和b,有时我想确定三个语句中的哪一个:a < b, a == bora > b为真。在像 C 或 C++ 这样的语言中,我会v在调用相应的函数或方法后得到一个 int 值。v < 0然后我可以通过检查是否,v == 0或 来确定以上哪些陈述是正确的v > 0。但在 Go 中,我必须至少进行两次比较(例如,先 testa < b然后 test a == b)才能找出三个语句中哪一个是正确的。我的问题是 Go 中是否有一种方法可以让我只进行一次比较?事实证明,此功能称为三向比较。
查看完整描述

3 回答

?
牛魔王的故事

TA贡献1830条经验 获得超3个赞

尽管这个比较器函数存在于strings包 ( strings.Compare()) 中,但它的文档也建议不要使用它:

Compare 返回一个按字典顺序比较两个字符串的整数。如果 a==b,结果将为 0,如果 a < b,则结果为 -1,如果 a > b,则结果为 +1。

包含比较只是为了与包字节对称。使用内置的字符串比较运算符 ==、<、> 等通常更清晰、更快。

为什么不实用strings.Compare()

有几个原因。

首先,在这种Compare()实用/常见的语言中,通常这些语言支持完全基于具有此签名的函数的排序。

例如,在 Java 中有一个Comparator接口,您可以将其传递给Collections.sort(). 因此,在 Java 中,您被迫拥有/实现这种比较(返回-1,01)。

在 Go 中,排序不是基于这样的比较函数。在 Go 中,排序是基于一个Less(i, j int) bool基本比较的函数a[i] < a[j],它只是“是不是少了?”。为此,你不需要strings.Compare(),你只需要a < b

第二个原因:strings.Compare()没有刻意优化,所以你不习惯使用它。的实施strings.Compare()有这样的评论:

// NOTE(rsc): This function does NOT call the runtime cmpstring function,

// because we do not want to provide any performance justification for

// using strings.Compare. Basically no one should use strings.Compare.

// As the comment above says, it is here only for symmetry with package bytes.

// If performance is important, the compiler should be changed to recognize

// the pattern so that all code doing three-way comparisons, not just code

// using strings.Compare, can benefit.

这意味着这a < b将比调用更快strings.Compare(a, b)。


第三, 的返回值strings.Compare()是一个整数,携带是否a小于b、a等于b或a大于的信息b。如果您确实需要使用所有 3 个分支(不仅仅是“less”或“equal”分支),您通常需要对 的返回值做进一步检查,就像strings.Compare()这个简单的例子:


switch strings.Compare("a", "b") {

case -1:

    fmt.Println("less")

case 0:

    fmt.Println("equal")

case 1: // or default:

    fmt.Println("greater")

}

现在,如果您考虑一下:比较首先在内部执行strings.Compare(),然后在您的代码中再次执行(比较返回值)。这是多余的,而且性能也很差。


上面可以这样写(这样会更快):


switch {

case a == b:

    fmt.Println("equal")

case a < b:

    fmt.Println("less")

default:

    fmt.Println("greater")

}

更多关于效率

如前所述,strings.Compare()没有刻意针对性能进行优化。但是Go的排序库不需要-10,1对字符串进行排序的结果,只需要 , 的结果a < b即可,获取效率与Compare()其他语言获取 的结果一样。

还要注意,strings.Compare()首先检查是否相等a == b,只有当它们不相等时才进行检查a < b。这一点很重要,因为stringGo 中的值存储了 the 的长度string,这意味着如果 2 个字符串的长度不同,则可以立即确定它们不相等。C 和 C++ 使用\0以 - 结尾的字符串值,这意味着判断 2 个字符串是否相等总是需要比较整个字符串,即使一个是一千个字符而另一个是少一个。实际上这并不完全正确,因为如果在比较字符时检测到不匹配,则比较结束,但这可能仍然比比较 2 个整数慢很多。


查看完整回答
反对 回复 2023-04-24
?
慕婉清6462132

TA贡献1804条经验 获得超2个赞

Go 是由程序员为程序员设计的。如果你想要一个 Cstrcmp函数,用 Go 写一个。


例如,


package main


import "fmt"


func strcmp(s1, s2 string) int {

    lens := len(s1)

    if lens > len(s2) {

        lens = len(s2)

    }

    for i := 0; i < lens; i++ {

        if s1[i] != s2[i] {

            return int(s1[i]) - int(s2[i])

        }

    }

    return len(s1) - len(s2)

}


func main() {

    tests := []struct {

        s1, s2 string

        cmp    int

    }{

        {"", "", 0},

        {"a", "a", 0},

        {"a", "b", -1},

        {"b", "a", +1},

        {"a", "aa", -1},

        {"aa", "a", 1},

    }

    for _, t := range tests {

        cmp := strcmp(t.s1, t.s2)

        fmt.Printf("%q %q %d %t\n", t.s1, t.s2, cmp, cmp == t.cmp)

    }

}

输出:


"" "" 0 true

"a" "a" 0 true

"a" "b" -1 true

"b" "a" 1 true

"a" "aa" -1 true

"aa" "a" 1 true

GNU C 库 (glibc):strcmp.c


查看完整回答
反对 回复 2023-04-24
?
慕的地10843

TA贡献1785条经验 获得超8个赞

在没有附加函数的情况下比较字符串在 Go 中就像一个魅力:


log.Println("as" > "ab") // true

log.Println("ab" == "ab") // true

log.Println("abc" < "abd") // true

回答您的问题:如果您想使用任何类型的函数(例如strings.Compare),那么您将获得一个具有三种状态的变量(即-1, 0, 1),最终您将不得不比较这三种状态。因此,当我们谈论字符串比较时,您无法避免比较少于两次。


查看完整回答
反对 回复 2023-04-24
  • 3 回答
  • 0 关注
  • 118 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信