英文:
What is the correct way to find the min between two integers in Go?
问题
我在我的程序中导入了math库,并尝试以以下方式找到三个数字的最小值:
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行:
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)]
}
英文:
I imported the math library in my program, and I was trying to find the minimum of three numbers in the following way:
v1[j+1] = math.Min(v1[j]+1, math.Min(v0[j+1]+1, v0[j]+cost))
where v1 is declared as:
t := "stackoverflow"
v1 := make([]int, len(t)+1)
However, when I run my program I get the following error:
./levenshtein_distance.go:36: cannot use int(v0[j + 1] + 1) (type int) as type float64 in argument to math.Min
I thought it was weird because I have another program where I write
fmt.Println(math.Min(2,3))
and that program outputs 2
without complaining.
so I ended up casting the values as float64, so that math.Min
could work:
v1[j+1] = math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost)))
With this approach, I got the following error:
./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
so to get rid of the problem, I just casted the result back to int
I thought this was extremely inefficient and hard to read:
v1[j+1] = int(math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost))))
I also wrote a small minInt
function, but I think this should be unnecessary because the other programs that make use of math.Min
work just fine when taking integers, so I concluded this has to be a problem of my program and not the library per se.
Is there anything that I'm doing terrible wrong?
Here's a program that you can use to reproduce the issues above, line 36 specifically:
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)]
}
答案1
得分: 134
在Go 1.18之前,一次性函数是标准的方法;例如,stdlib的sort.go在文件的顶部执行此操作:
func min(a, b int) int {
if a < b {
return a
}
return b
}
你可能仍然希望或需要使用这种方法,以便你的代码可以在Go 1.18以下的版本上运行!
从Go 1.18开始,你可以编写一个通用的min
函数,它在运行时与手写的单类型版本一样高效,但可以使用任何具有<
和>
运算符的类型:
func min[T constraints.Ordered](a, b T) T {
if a < b {
return a
}
return b
}
func main() {
fmt.Println(min(1, 2))
fmt.Println(min(1.5, 2.5))
fmt.Println(min("Hello", "世界"))
}
已经有讨论更新stdlib以添加现有函数的通用版本,但如果发生这种情况,那将是在以后的版本中。
math.Min(2, 3)
之所以有效,是因为Go中的数值常量是无类型的。然而,要注意不要将float64作为通用数字类型处理,因为转换为float64的整数超过2^53
将会四舍五入。
英文:
Until Go 1.18 a one-off function was the standard way; for example, the stdlib's sort.go does it near the top of the file:
func min(a, b int) int {
if a < b {
return a
}
return b
}
You might still want or need to use this approach so your code works on Go versions below 1.18!
Starting with Go 1.18, you can write a generic min
function which is just as efficient at run time as the hand-coded single-type version, but works with any type with <
and >
operators:
func min[T constraints.Ordered](a, b T) T {
if a < b {
return a
}
return b
}
func main() {
fmt.Println(min(1, 2))
fmt.Println(min(1.5, 2.5))
fmt.Println(min("Hello", "世界"))
}
There's been discussion of updating the stdlib to add generic versions of existing functions, but if that happens it won't be until a later version.
math.Min(2, 3)
happened to work because numeric constants in Go are untyped. Beware of treating float64s as a universal number type in general, though, since integers above 2^53
will get rounded if converted to float64.
答案2
得分: 22
没有为整数提供内置的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
}
英文:
There is no built-in min or max function for integers, but it’s simple to write your own. Thanks to support for variadic functions we can even compare more integers with just one call:
func MinOf(vars ...int) int {
min := vars[0]
for _, i := range vars {
if min > i {
min = i
}
}
return min
}
Usage:
MinOf(3, 9, 6, 2)
Similarly here is the max function:
func MaxOf(vars ...int) int {
max := vars[0]
for _, i := range vars {
if max < i {
max = i
}
}
return max
}
答案3
得分: 7
根据问题59488,Go 1.21(2023年第三季度)将包含两个新的内置命令,如CL 498495所示:
// max内置函数返回一组[cmp.Ordered]类型参数中的最大值。至少需要一个参数。
func max[T cmp.Ordered](x T, y ...T) T
// min内置函数返回一组[cmp.Ordered]类型参数中的最小值。至少需要一个参数。
func min[T cmp.Ordered](x T, y ...T) T
根据这里的文档:
> ## Min和max
>
> 内置函数min
和max
计算有序类型的一组固定参数中的最小值或最大值。
必须至少有一个参数。
>
> 与运算符适用相同的类型规则:
>
> - 对于有序参数x
和y
,如果x + y
有效,则min(x, y)
有效,并且min(x, y)
的类型是x + y
的类型(max
同理)。
> - 如果所有参数都是常量,则结果是常量。
>
> go > var x, y int > m := min(x) // m == x > m := min(x, y) // m是x和y中较小的值 > m := max(x, y, 10) // m是x和y中较大的值,但至少为10 > c := max(1, 2.0, 10) // c == 10.0(浮点数类型) > f := max(0, float32(x)) // f的类型是float32 > var s []string > _ = min(s...) // 无效:不允许使用切片参数 > t := max("","foo","bar") // t == "foo"(字符串类型) >
>
> 对于数值参数,min和max是可交换和可结合的:
>
> go > min(x, y) == min(y, x) > min(x, y, z) == min(min(x, y), z) == min(x, min(y, z)) >
英文:
Following issue 59488, Go 1.21 (Q3 2023) will include, as shown by CL 498495 two new builtin commands:
// The max built-in function returns the largest value of a fixed number of
// arguments of [cmp.Ordered] types. There must be at least one argument.
func max[T cmp.Ordered](x T, y ...T) T
// The min built-in function returns the smallest value of a fixed number of
// arguments of [cmp.Ordered] types. There must be at least one argument.
func min[T cmp.Ordered](x T, y ...T) T
> ## Min and max
>
> The built-in functions min
and max
compute the smallest—or largest, respectively—value of a fixed number of arguments of ordered types.
There must be at least one argument.
>
> The same type rules as for operators apply:
>
> - for ordered arguments x
and y
, min(x, y)
is valid if x + y
is valid, and the type of min(x, y)
is the type of x + y
(and similarly for max).
> - If all arguments are constant, the result is constant.
>
> go
> var x, y int
> m := min(x) // m == x
> m := min(x, y) // m is the smaller of x and y
> m := max(x, y, 10) // m is the larger of x and y but at least 10
> c := max(1, 2.0, 10) // c == 10.0 (floating-point kind)
> f := max(0, float32(x)) // type of f is float32
> var s []string
> _ = min(s...) // invalid: slice arguments are not permitted
> t := max("", "foo", "bar") // t == "foo" (string kind)
>
>
> For numeric arguments, min and max are commutative and associative:
>
> go
> min(x, y) == min(y, x)
> min(x, y, z) == min(min(x, y), z) == min(x, min(y, z))
>
答案4
得分: 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])
}
输出:
1
英文:
For example,
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])
}
Output:
<pre>
1
</pre>
答案5
得分: 3
根据接受的答案,通过在Go 1.18中引入泛型,现在可以编写一个通用函数,为不同的数值类型提供最小值/最大值(语言本身没有内置的函数)。通过可变参数,我们可以支持比较两个元素或更长的元素列表。
func Min[T constraints.Ordered](args ...T) T {
min := args[0]
for _, x := range args {
if x < min {
min = x
}
}
return min
}
func Max[T constraints.Ordered](args ...T) T {
max := args[0]
for _, x := range args {
if x > max {
max = x
}
}
return max
}
示例调用:
Max(1, 2) // 2
Max(4, 5, 3, 1, 2) // 5
英文:
As the accepted answer states, with the introduction of generics in go 1.18 it's now possible to write a generic function that provides min/max for different numeric types (there is not one built into the language). And with variadic arguments we can support comparing 2 elements or a longer list of elements.
func Min[T constraints.Ordered](args ...T) T {
min := args[0]
for _, x := range args {
if x < min {
min = x
}
}
return min
}
func Max[T constraints.Ordered](args ...T) T {
max := args[0]
for _, x := range args {
if x > max {
max = x
}
}
return max
}
example calls:
Max(1, 2) // 2
Max(4, 5, 3, 1, 2) // 5
答案6
得分: 2
虽然这个问题很旧,但也许我的包imath对于那些不喜欢重新发明轮子的人可能会有帮助。这个包中有一些函数,可以找到两个整数的最小值:ix.Min
(用于int
)、i8.Min
(用于int8
)、ux.Min
(用于uint
)等等。可以通过go get
获取该包,并通过URL在项目中导入,然后使用typeabbreviation.FuncName
来引用函数,例如:
package main
import (
"fmt"
"<Full URL>/go-imath/ix"
)
func main() {
a, b := 45, -42
fmt.Println(ix.Min(a, b)) // 输出:-42
}
英文:
Though the question is quite old, maybe my package imath can be helpful for someone who does not like reinventing a bicycle. There are few functions, finding minimal of two integers: ix.Min
(for int
), i8.Min
(for int8
), ux.Min
(for uint
) and so on. The package can be obtained with go get
, imported in your project by URL and functions referred as typeabbreviation.FuncName
, for example:
package main
import (
"fmt"
"<Full URL>/go-imath/ix"
)
func main() {
a, b := 45, -42
fmt.Println(ix.Min(a, b)) // Output: -42
}
答案7
得分: 0
你可以使用https://github.com/pkg/math:
import (
"fmt"
"github.com/pkg/math"
)
func main() {
a, b := 45, -42
fmt.Println(math.Min(a, b)) // 输出:-42
}
英文:
Could use https://github.com/pkg/math:
import (
"fmt"
"github.com/pkg/math"
)
func main() {
a, b := 45, -42
fmt.Println(math.Min(a, b)) // Output: -42
}
答案8
得分: 0
如果你想找到一组N个整数的最小值(假设N > 0),你可以使用以下代码(使用Go语言):
import "sort"
func min(set []int) int {
sort.Slice(set, func(i, j int) bool {
return set[i] < set[j]
})
return set[0]
}
其中min
函数的第二个参数是你的less
函数,即用于判断传入切片中的元素i
是否小于元素j
的函数。
你可以在Go Playground上查看示例:https://go.dev/play/p/lyQYlkwKrsA
英文:
If you want the minimum of a set of N integers you can use (assuming N > 0):
import "sort"
func min(set []int) int {
sort.Slice(set, func(i, j int) bool {
return set[i] < set[j]
})
return set[0]
}
Where the second argument to min
function is your less
function, that is, the function that decides when an element i
of the passed slice is less than an element j
Check it out here in Go Playground: https://go.dev/play/p/lyQYlkwKrsA
答案9
得分: -1
这是一个非常常见的问题,似乎所有的答案都已经过时了。自从Go 1.21版本以后,现在有一个内置的min
函数(以及max
函数)。如果你正在使用Go 1.21+版本,就使用它来替代旧的解决方法。
min
函数不需要导入,支持任意数量的参数(可变参数函数),可以接受整数、浮点数或字符串。
n := min(1, -4, 2)
fmt.Println(m)
// -4
英文:
This is a very common question, and seems like all of the answers are out of date. Ever since Go 1.21, there's now a built-in min
function (along with max
). If you're using Go 1.21+, use it instead of the older work-arounds.
min
does not need to be imported, supports as many arguments (variadic function) and can take integers, floats or strings.
n := min(1, -4, 2)
fmt.Println(m)
// -4
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论