Каков правильный способ найти мин между двумя целыми числами в Go?

Я импортировал математическую библиотеку в свою программу, и я пытался найти минимум три числа следующим образом:

v1[j+1] = math.Min(v1[j]+1, math.Min(v0[j+1]+1, v0[j]+cost))

где v1 объявляется как:

t := "stackoverflow"
v1 := make([]int, len(t)+1)

Однако, когда я запускаю свою программу, я получаю следующую ошибку:

./levenshtein_distance.go:36: cannot use int(v0[j + 1] + 1) (type int) as type float64 in argument to math.Min

Я думал, что это было странно, потому что у меня есть другая программа, где я пишу

fmt.Println(math.Min(2,3))

и эта программа выводит 2 без жалоб.

поэтому я закончил тем, что листинг значения как float64, чтобы math.Min мог работать:

v1[j+1] = math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost)))

При таком подходе я получил следующую ошибку:

./levenshtein_distance.go:36: cannot use math.Min(int(v1[j] + 1), math.Min(int(v0[j + 1] + 1), int(v0[j] + cost))) (type float64) as type int in assignment

поэтому, чтобы избавиться от проблемы, я просто вернул результат в int

Я думал, что это крайне неэффективно и трудно читать:

v1[j+1] = int(math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost))))

Я также написал небольшую функцию minInt, но я думаю, что это должно быть ненужным, потому что другие программы, которые используют math.Min, отлично работают при наборе целых чисел, поэтому я пришел к выводу, что это проблема моей программы а не самой библиотеки.

Есть ли что-то, что я делаю ужасно неправильно?

Здесь программа, которую вы можете использовать для воспроизведения вышеперечисленных вопросов, строка 36, в частности: основной пакет

import (
    "math"
)

func main() {
    LevenshteinDistance("stackoverflow", "stackexchange")
}

func LevenshteinDistance(s string, t string) int {
    if s == t {
        return 0
    }
    if len(s) == 0 {
        return len(t)
    }
    if len(t) == 0 {
        return len(s)
    }

    v0 := make([]int, len(t)+1)
    v1 := make([]int, len(t)+1)

    for i := 0; i < len(v0); i++ {
        v0[i] = i
    }

    for i := 0; i < len(s); i++ {
        v1[0] = i + 1
        for j := 0; j < len(t); j++ {
            cost := 0
            if s[i] != t[j] {
                cost = 1
            }
            v1[j+1] = int(math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost))))
        }

        for j := 0; j < len(v0); j++ {
            v0[j] = v1[j]
        }
    }
    return v1[len(t)]
}

Ответ 1

Нет, я думаю, что писать что-то вроде этого хорошо: например, stdlib sort.go делает это в верхней части файла:

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

Ваша math.Min(2, 3) работала, потому что числовые константы в Go нетипизированы. Помимо того, что нужно просто избегать ненужного приведения, лучше не использовать функции с плавающей точкой для целых чисел, потому что не каждый int64 имеет точное представление float64те, что выше 2 ^ 53, не имеют).

Ответ 2

Например,

package main

import "fmt"

func min(x, y int) int {
    if x < y {
        return x
    }
    return y
}

func main() {
    t := "stackoverflow"
    v0 := make([]int, len(t)+1)
    v1 := make([]int, len(t)+1)
    cost := 1
    j := 0

    v1[j+1] = min(v1[j]+1, min(v0[j+1]+1, v0[j]+cost))

    fmt.Println(v1[j+1])
}

Вывод:

1

Ответ 3

Не существует встроенной функции min или max для целых чисел, но ее просто написать самостоятельно. Благодаря поддержке функций с переменными числами, мы можем даже сравнить больше целых чисел всего одним вызовом:

func MinOf(vars ...int) int {
    min := vars[0]

    for _, i := range vars {
        if min > i {
            min = i
        }
    }

    return min
}

Использование:

MinOf(3, 9, 6, 2)

Аналогично, здесь есть функция max:

func MaxOf(vars ...int) int {
    max := vars[0]

    for _, i := range vars {
        if max < i {
            max = i
        }
    }

    return max
}