在Go中找到两个整数之间的最小值的正确方法是什么?

ILi*_*cos 30 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)
Run Code Online (Sandbox Code Playgroud)

但是,当我运行我的程序时,我收到以下错误:

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

我觉得这很奇怪,因为我写了另一个程序

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)))
Run Code Online (Sandbox Code Playgroud)

通过这种方法,我收到以下错误:

./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
Run Code Online (Sandbox Code Playgroud)

所以为了摆脱这个问题,我只是把结果归还给了 int

我认为这是非常低效和难以阅读:

v1[j+1] = int(math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost))))
Run Code Online (Sandbox Code Playgroud)

我还写了一个小minInt函数,但我认为这应该是不必要的,因为其他程序在使用math.Min整数时很好地利用了工作,所以我得出结论,这必须是我的程序的问题,而不是库本身.

有什么我做错了吗?

这是一个可以用来重现上述问题的程序,第36行具体来说:package main

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)]
}
Run Code Online (Sandbox Code Playgroud)

two*_*two 47

不,我认为写这样的东西很好:例如,stdlib的sort.go靠近文件的顶部:

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}
Run Code Online (Sandbox Code Playgroud)

你的math.Min(2, 3)工作是因为Go中的数字常量是无类型的.除了避免不必要的转换之外,最好不要对整数使用浮点函数,因为不是每个2^53都有精确的math.Min(2, 3)表示(特别是2 ^ 53以上的那些).

  • 写这样的东西在大多数其他语言中都是不寻常的.因此,我想这个问题,至少我是如何在这里结束的.这不是我不能写min函数,而是我不敢相信它还没有... (78认同)
  • 如果你经常使用超过2个数字的min,你可以制作一个vararg版本的min,它简化了调用它的代码:例如:https://play.golang.org/p/v93gvbBEmT (2认同)
  • 需要编写这样的简单函数会导致代码膨胀吗?此外,一般来说,任何额外的代码,无论多么简单,都可能引入错误(可能是低级错误)。使用官方的东西会很好,因为我们可以更确定它的实现。 (2认同)

Von*_*onC 13

在问题 59488之后 ,Go 1.21(2023 年第 3 季度)将包含两个新的内置命令,如CL 498495所示:

\n
// The max built-in function returns the largest value of a fixed number of\n// arguments of [cmp.Ordered] types. There must be at least one argument.\nfunc max[T cmp.Ordered](x T, y ...T) T\n// The min built-in function returns the smallest value of a fixed number of\n// arguments of [cmp.Ordered] types. There must be at least one argument.\nfunc min[T cmp.Ordered](x T, y ...T) T\n
Run Code Online (Sandbox Code Playgroud)\n

如此处记录的

\n
\n

最小值和最大值

\n

内置函数minmax分别计算固定数量的有序类型参数的最小\xe2\x80\x94 或最大\xe2\x80\x94 值。
\n必须至少有一个参数。

\n

与运算符相同的类型规则适用:

\n
    \n
  • 对于有序参数xymin(x, y)如果x + y有效,则有效,并且 的类型min(x, y)是 的类型x + y(对于 max 也类似)。
  • \n
  • 如果所有参数都是常数,则结果也是常数。
  • \n
\n
var x, y int\nm := min(x)                 // m == x\nm := min(x, y)              // m is the smaller of x and y\nm := max(x, y, 10)          // m is the larger of x and y but at least 10\nc := max(1, 2.0, 10)        // c == 10.0 (floating-point kind)\nf := max(0, float32(x))     // type of f is float32\nvar s []string\n_ = min(s...)               // invalid: slice arguments are not permitted\nt := max("", "foo", "bar")  // t == "foo" (string kind)\n
Run Code Online (Sandbox Code Playgroud)\n

对于数字参数,min 和 max 是可交换的和结合的:

\n
min(x, y)    == min(y, x)\nmin(x, y, z) == min(min(x, y), z) == min(x, min(y, z))\n
Run Code Online (Sandbox Code Playgroud)\n
\n


Ser*_*ean 7

没有用于整数的内置min或max函数,但是编写自己的函数很简单。由于支持可变参数函数,我们甚至可以通过一次调用来比较更多整数:

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

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

    return min
}
Run Code Online (Sandbox Code Playgroud)

用法:

MinOf(3, 9, 6, 2)
Run Code Online (Sandbox Code Playgroud)

同样,这里是max函数:

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

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

    return max
}
Run Code Online (Sandbox Code Playgroud)


pet*_*rSO 5

例如,

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])
}
Run Code Online (Sandbox Code Playgroud)

输出:

1

  • 每次你需要 min 为 float64 的其他类型时,golang 都会让你重写轮子? (99认同)
  • 这就是当宣称的“简单”导致真正的复杂性时。 (38认同)