英文:
Implementing fizz buzz of higher order using maps in go lang?
问题
我正在尝试使用Go语言中的映射实现Fizz Buzz问题。然而,这段代码在工作中需要改进。由于for
循环遍历映射,它会持续打印出不需要的和冗余的结果。我尝试了很多解决方案,但都失败了。在不使用键的切片的帮助下,这种改进可行吗?
package main
import "fmt"
func fizzbuzz(i int) {
myMap := make(map[int]string)
myMap[3] = "fizz"
myMap[5] = "buzz"
myMap[15] = "fizzbuzz"
for k, v := range myMap {
if i%k == 0 {
fmt.Printf("%v \n", v)
} else {
fmt.Printf("%v \n", i)
}
}
}
func main() {
for i := 1; i < 10000; i++ {
fizzbuzz(i)
}
}
请注意,我只翻译了你提供的代码部分,其他内容不包括在内。
英文:
I am trying to implement the fizz buzz problem using maps in go lang. However, this code requires improvement in its working. It keeps on printing undesired and redundant results due to the for
loop that iterates over the map. I tried a lot of solutions but failed. Is it feasible without using any help of a slice of keys?
package main
import "fmt"
func fizzbuzz(i int) {
myMap:= make(map[int]string)
myMap[3] = "fizz"
myMap[5] = "buzz"
myMap[15] = "fizzbuzz"
for k,v:= range myMap{
if i%k==0 {fmt.Printf("%v \n",v)
} else {fmt.Printf("%v \n",i)}
}
}
func main() {
for i:=1;i<10000;i++ {
fizzbuzz(i)
}
}
答案1
得分: 1
使用映射
根据你的规则集,整个for
循环应该用于决定是否用一个单词替换i
数值。但是你在每次迭代中都发出了一个结果。for
最多应该发出一个结果。如果i
不能被任何键整除,则应该发出i
。
键可以是其他键的倍数(例如15 = 3 * 5
),如果i
可以被这样的键整除,我们希望发出与最大键关联的单词。因此,for
循环不应该发出任何内容,因为如果你找到一个好的键,可能还有一个更大的键。所以循环只需找到最大的好键。
在循环之后,你可以检查是否找到了任何好的键,如果找到了,就发出与之关联的单词,否则发出该数字:
var rules = map[int]string{
3: "fizz",
5: "buzz",
15: "fizzbuzz",
}
func fizzbuzz(i int) {
max := -1
for k := range rules {
if i%k == 0 && k > max {
max = k
}
}
if max < 0 {
fmt.Println(i)
} else {
fmt.Println(rules[max])
}
}
func main() {
for i := 1; i < 100; i++ {
fizzbuzz(i)
}
}
输出结果(在[Go Playground][1]上尝试):
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz
fizz
...
### 使用有序切片
如果按键降序排序规则,可以获得更好的性能,这样你可以按照这个顺序(从大到小)检查键,然后第一个符合条件的键将是最大的。因此,你可以立即发出结果并返回。
如果循环后继续执行,我们知道没有好的键,我们可以发出`i`数值:
```go
var rules = []struct {
n int
word string
}{
{15, "fizzbuzz"},
{5, "buzz"},
{3, "fizz"},
}
func fizzbuzz(i int) {
for _, rule := range rules {
if i%rule.n == 0 {
fmt.Println(rule.word)
return
}
}
fmt.Println(i)
}
在[Go Playground][2]上尝试。
### 通用方法(排除规则中的倍数)
尽管你最初的规则集中包含了`15 = 3 * 5`,但实际上不应该这样;你只需要列出`3`和`5`,`15`应该是隐含的。
在这种情况下,你当然必须检查所有的规则,因为每个好的键都应该发出一个单词。你还必须记住是否找到了一个好的键,只有在找不到好的键时才发出`i`数值。
你可以这样做:
```go
var rules = []struct {
n int
word string
}{
{3, "fizz"},
{5, "buzz"},
}
func fizzbuzz(i int) {
found := false
for _, rule := range rules {
if i%rule.n == 0 {
found = true
fmt.Print(rule.word)
}
}
if !found {
fmt.Print(i)
}
fmt.Println()
}
在[Go Playground][3]上尝试。
注意:在这个解决方案中,你也可以使用映射而不是切片;我使用切片的原因是,如果有多个好的键,发出的单词将始终按照相同的顺序(由增加的键定义),因为映射中的键的迭代顺序未定义。有关详细信息,请参见https://stackoverflow.com/questions/28930416/why-cant-go-iterate-maps-in-insertion-order/28931555#28931555
[1]: https://play.golang.org/p/xO2uVXqbBz
[2]: https://play.golang.org/p/50efZx7Q0e
[3]: https://play.golang.org/p/zPltHuGl-R
<details>
<summary>英文:</summary>
### With a map
With your rule set, the entire `for` loop should be to decide if the `i` number is to be replaced with a word. But you emit a result in each iteration. At most one result should be emitted by the `for`. If `i` is not dividable by any of the keys, then `i` should be emitted.
Keys may be multiples of others (e.g. `15 = 3 * 5`), and if the `i` number is dividable by such a key, we want to emit the word associated with the greatest key. So the `for` loop should not emit anything, because if you find a good key, there may be a greater one. So the loop should just find the greatest good key.
After the loop you can check if any good key was found, and if so, emit the word associated with it, else emit the number:
var rules = map[int]string{
3: "fizz",
5: "buzz",
15: "fizzbuzz",
}
func fizzbuzz(i int) {
max := -1
for k := range rules {
if i%k == 0 && k > max {
max = k
}
}
if max < 0 {
fmt.Println(i)
} else {
fmt.Println(rules[max])
}
}
func main() {
for i := 1; i < 100; i++ {
fizzbuzz(i)
}
}
Output (try it on the [Go Playground][1]):
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz
fizz
...
### With an ordered slice
You can get better performance if the rules are sorted by the keys descending, in which case you can check the keys in that order (greatest first), and then the first that qualifies will be the greatest. So you can emit the result immediately, and return.
If execution continues after the loop, we know no keys were good, we can emit the `i` number:
var rules = []struct {
n int
word string
}{
{15, "fizzbuzz"},
{5, "buzz"},
{3, "fizz"},
}
func fizzbuzz(i int) {
for _, rule := range rules {
if i%rule.n == 0 {
fmt.Println(rule.word)
return
}
}
fmt.Println(i)
}
Try this on the [Go Playground][2].
### General (excluding multiples from rules)
Although you started with a rule set where `15 = 3 * 5` was included in the rules, this should not be the case; you should only list `3` and `5`, `15` should be implicit.
In this case, you have to check all the rules of course, because each good key should emit a word. And you have to remember if a good key was found, and only emit the `i` number otherwise.
This is how you can do it:
var rules = []struct {
n int
word string
}{
{3, "fizz"},
{5, "buzz"},
}
func fizzbuzz(i int) {
found := false
for _, rule := range rules {
if i%rule.n == 0 {
found = true
fmt.Print(rule.word)
}
}
if !found {
fmt.Print(i)
}
fmt.Println()
}
Try it on the [Go Playground][3].
Note: in this solution you could also use a map instead of the slice; the reason why I used a slice is so that in case of multiple good keys the emitted words will always be in the same order (defined by increasing keys), as iteration order of keys in a map is not defined. For details, see https://stackoverflow.com/questions/28930416/why-cant-go-iterate-maps-in-insertion-order/28931555#28931555
[1]: https://play.golang.org/p/xO2uVXqbBz
[2]: https://play.golang.org/p/50efZx7Q0e
[3]: https://play.golang.org/p/zPltHuGl-R
</details>
# 答案2
**得分**: 0
如前所述,在Go语言中,映射中项目的顺序是不确定的。以下是一些简单的解决方案:
```go
func fizzbuzz(n int) {
for i := 1; i <= n; i++ {
switch {
case i%15 == 0:
println("fizzbuzz")
case i%5 == 0:
println("buzz")
case i%3 == 0:
println("fizz")
default:
println(i)
}
}
}
func fizzbuzzList(n int) []string {
var res []string
for i := 1; i <= n; i++ {
switch {
case i%15 == 0:
res = append(res, "fizzbuzz")
case i%5 == 0:
res = append(res, "buzz")
case i%3 == 0:
res = append(res, "fizz")
default:
res = append(res, strconv.Itoa(i))
}
}
return res
}
func fizzbuzzLazy(n int) chan string {
var res = make(chan string)
go func() {
for i := 1; i <= n; i++ {
switch {
case i%15 == 0:
res <- "fizzbuzz"
case i%5 == 0:
res <- "buzz"
case i%3 == 0:
res <- "fizz"
default:
res <- strconv.Itoa(i)
}
}
close(res)
}()
return res
}
用法示例:
fizzbuzz(20)
for _, v := range fizzbuzzList(20) {
println(v)
}
for v := range fizzbuzzLazy(20) {
println(v)
}
英文:
As mentioned, the order of items in a map, is not deterministic in Go. Though here are some simple solutions:
func fizzbuzz(n int) {
for i := 1; i <= n; i++ {
switch {
case i%15 == 0:
println("fizzbuzz")
case i%5 == 0:
println(`buzz`)
case i%3 == 0:
println(`fizz`)
default:
println(i)
}
}
}
func fizzbuzzList(n int) []string {
var res []string
for i := 1; i <= n; i++ {
switch {
case i%15 == 0:
res = append(res, `fizzbuzz`)
case i%5 == 0:
res = append(res, `buzz`)
case i%3 == 0:
res = append(res, `fizz`)
default:
res = append(res, strconv.Itoa(i))
}
}
return res
}
func fizzbuzzLazy(n int) chan string {
var res = make(chan string)
go func() {
for i := 1; i <= n; i++ {
switch {
case i%15 == 0:
res <- `fizzbuzz`
case i%5 == 0:
res <- `buzz`
case i%3 == 0:
res <- `fizz`
default:
res <- strconv.Itoa(i)
}
}
close(res)
}()
return res
}
And usage:
fizzbuzz(20)
for _, v := range fizzbuzzList(20) {
println(v)
}
for v := range fizzbuzzLazy(20) {
println(v)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论