Иди сравни строки - PullRequest
       5

Иди сравни строки

0 голосов
/ 16 октября 2018

Учитывая две строки a и b, иногда я хочу определить, какое из трех утверждений: a < b, a == b или a > b является истинным.

На языке, подобномC или C ++, я получу значение типа int v после одного вызова соответствующей функции или метода.Затем я могу определить, какое из приведенных выше утверждений является верным, проверяя, v < 0, v == 0 или v > 0.

Но в Go я должен сделать как минимум два сравнения (например, первый тест a < bзатем проверьте a == b), чтобы выяснить, какое из трех утверждений является верным.

Мой вопрос заключается в том, есть ли способ в Go, чтобы я мог просто провести одно сравнение?

Оказывается, эта функция называется трехстороннее сравнение .

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

Несмотря на то, что эта функция сравнения существует в пакете strings (strings.Compare()), даже ее документ не рекомендует использовать ее:

Compare возвращает целое число, сравнивая две строки лексикографически.Результат будет 0, если a == b, -1, если a b.

Сравнение включено только для симметрии с байтами пакета.Обычно понятнее и всегда быстрее использовать встроенные операторы сравнения строк ==, <,> и т. Д.

Почему нецелесообразно использовать strings.Compare()?

Есть несколько причин.

Во-первых, в языках, где этот вид Compare() является практичным / распространенным, обычно те языки поддерживают сортировку, которая основана именно на функции с этой сигнатурой.

Например, в Java есть интерфейс Comparator, который вы можете передать Collections.sort().Таким образом, в Java вы вынуждены иметь / реализовать такое сравнение (которое возвращает -1, 0 или 1).

В Go сортировка не основана на такой функции компаратора.В Go сортировка основана на единственной функции Less(i, j int) bool, которая, в основном, a[i] < a[j] сравнения, это просто "это меньше?".Для этого вам не нужно strings.Compare(), вам нужно только a < b.Например, см. sort.Slice().

Вторая причина: 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 ветви (не только ветку «меньше» или «равно»), вам обычно необходимо провести дополнительную проверку возвращаемого значения 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 не требуется результат -1, 0, 1 для сортировки строк, а только результат a < b, который можно получить с той же эффективностью, что и результат Compare() в другомязыки.

Также обратите внимание, что strings.Compare() сначала проверяет равенство a == b, и только если они не равны, продолжается проверка a < b.Это важно, потому что значения string в Go хранят длину string (подробности см. reflect.StringHeader), что означает, что если 2 строки имеют разную длину, можно сразу решить, что онине равныC и C ++ используют \0 -определенные строковые значения, что означает, что для того, чтобы определить, равны ли 2 строки, всегда требуется сравнивать целые строки, даже если одна - тысяча символов, а другая - на одну меньше.На самом деле это не совсем верно, потому что, если при сравнении символов обнаруживается несоответствие, сравнение заканчивается, но это все равно может быть намного медленнее, чем сравнение двух целых чисел.

Также см. Связанный вопрос: Использованиесимвол == в golang и использование цикла для сравнения, если строка a равна строке b, какая производительность лучше?

0 голосов
/ 16 октября 2018

Go был разработан программистами для программистов.Если вам нужна функция C strcmp, напишите ее на языке 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)
    }
}

Детская площадка: https://play.golang.org/p/EAzV5_ouDI2

Вывод:

"" "" 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

0 голосов
/ 16 октября 2018

А как насчет функции сравнения?

Голанг Док

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...