What is the correct way to find the min between two integers in Go?

huangapple go评论87阅读模式
英文:

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 := &quot;stackoverflow&quot;
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 (
	&quot;math&quot;
)

func main() {
	LevenshteinDistance(&quot;stackoverflow&quot;, &quot;stackexchange&quot;)
}

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 &lt; len(v0); i++ {
		v0[i] = i
	}

	for i := 0; i &lt; len(s); i++ {
		v1[0] = i + 1
		for j := 0; j &lt; 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 &lt; 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 &lt; 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 &lt; and &gt; operators:

func min[T constraints.Ordered](a, b T) T {
	if a &lt; b {
		return a
	}
	return b
}

func main() {
	fmt.Println(min(1, 2))
	fmt.Println(min(1.5, 2.5))
	fmt.Println(min(&quot;Hello&quot;, &quot;世界&quot;))
}

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 &gt; 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 &lt; i {
			max = i
		}
	}

	return max
}

答案3

得分: 7

根据问题59488Go 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
>
> 内置函数minmax计算有序类型的一组固定参数中的最小值或最大值。
必须至少有一个参数。
>
> 与运算符适用相同的类型规则:
>
> - 对于有序参数xy,如果x + y有效,则min(x, y)有效,并且min(x, y)的类型是x + y的类型(max同理)。
> - 如果所有参数都是常量,则结果是常量。
>
> go &gt; var x, y int &gt; m := min(x) // m == x &gt; m := min(x, y) // m是x和y中较小的值 &gt; m := max(x, y, 10) // m是x和y中较大的值,但至少为10 &gt; c := max(1, 2.0, 10) // c == 10.0(浮点数类型) &gt; f := max(0, float32(x)) // f的类型是float32 &gt; var s []string &gt; _ = min(s...) // 无效:不允许使用切片参数 &gt; t := max("","foo","bar") // t == "foo"(字符串类型) &gt;
>
> 对于数值参数,min和max是可交换和可结合的:
>
> go &gt; min(x, y) == min(y, x) &gt; min(x, y, z) == min(min(x, y), z) == min(x, min(y, z)) &gt;

英文:

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

As documented here:

> ## 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
&gt; var x, y int
&gt; m := min(x) // m == x
&gt; m := min(x, y) // m is the smaller of x and y
&gt; m := max(x, y, 10) // m is the larger of x and y but at least 10
&gt; c := max(1, 2.0, 10) // c == 10.0 (floating-point kind)
&gt; f := max(0, float32(x)) // type of f is float32
&gt; var s []string
&gt; _ = min(s...) // invalid: slice arguments are not permitted
&gt; t := max(&quot;&quot;, &quot;foo&quot;, &quot;bar&quot;) // t == &quot;foo&quot; (string kind)
&gt;

>
> For numeric arguments, min and max are commutative and associative:
>
> go
&gt; min(x, y) == min(y, x)
&gt; min(x, y, z) == min(min(x, y), z) == min(x, min(y, z))
&gt;

答案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 &quot;fmt&quot;

func min(x, y int) int {
	if x &lt; y {
		return x
	}
	return y
}

func main() {
	t := &quot;stackoverflow&quot;
	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 &lt; min {
			min = x
		}
	}
	return min
}

func Max[T constraints.Ordered](args ...T) T {
	max := args[0]
	for _, x := range args {
		if x &gt; 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 (
	&quot;fmt&quot;
	&quot;&lt;Full URL&gt;/go-imath/ix&quot;
)

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 (
    &quot;fmt&quot;
    &quot;github.com/pkg/math&quot;
)

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 &quot;sort&quot;

func min(set []int) int {
	sort.Slice(set, func(i, j int) bool {
		return set[i] &lt; 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

huangapple
  • 本文由 发表于 2014年12月17日 08:22:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/27516387.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定