编写一个深度为d的嵌套迭代器。

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

Writing a nested iterator of depth d

问题

如何实现一个带有深度参数的嵌套迭代器。当深度为1时,它就是一个简单的迭代器,类似于简单的for循环。

  1. func Iter(depth int) chan string {
  2. ch := make(chan string)
  3. go func() {
  4. if depth == 1 {
  5. for i := 1; i < 60; i++ {
  6. ch <- fmt.Sprintf("%d", i)
  7. }
  8. } else {
  9. subIter := Iter(depth - 1)
  10. for i := 1; i < 60; i++ {
  11. for sub := range subIter {
  12. ch <- fmt.Sprintf("%s,%d", sub, i)
  13. }
  14. subIter = Iter(depth - 1)
  15. }
  16. }
  17. close(ch)
  18. }()
  19. return ch
  20. }

输出为1,2,3...59

当深度为2时,输出为"1,1" "1,2" ... "1,59" "2,1" ... "59,59"

当深度为3时,输出为"1,1,1" ... "59,59,59"

这样可以避免使用嵌套的for循环。

英文:

How to realize a nested iterator that takes a depth argument. A simple iterator would be when depth = 1. it is a simple iterator which runs like a simple for loop.

  1. func Iter () chan int {
  2. ch := make(chan int);
  3. go func () {
  4. for i := 1; i &lt; 60; i++ {
  5. ch &lt;- i
  6. }
  7. close(ch)
  8. } ();
  9. return ch
  10. }

Output is 1,2,3...59

For depth = 2 Output would be &quot;1,1&quot; &quot;1,2&quot; ... &quot;1,59&quot; &quot;2,1&quot; ... &quot;59,59&quot;

For depth = 3 Output would be &quot;1,1,1&quot; ... &quot;59,59,59"

I want to avoid a nested for loop. What is the solution here ?

答案1

得分: 2

我不知道是否可以避免嵌套循环,但是一种解决方案是使用管道的流水线。例如:

  1. const ITER_N = 60
  2. // ----------------
  3. func _goFunc1(out chan string) {
  4. for i := 1; i < ITER_N; i++ {
  5. out <- fmt.Sprintf("%d", i)
  6. }
  7. close(out)
  8. }
  9. func _goFuncN(in chan string, out chan string) {
  10. for j := range in {
  11. for i := 1; i < ITER_N; i++ {
  12. out <- fmt.Sprintf("%s,%d", j, i)
  13. }
  14. }
  15. close(out)
  16. }
  17. // ----------------
  18. // 创建流水线
  19. func IterDepth(d int) chan string {
  20. c1 := make(chan string)
  21. go _goFunc1(c1)
  22. var c2 chan string
  23. for ; d > 1; d-- {
  24. c2 = make(chan string)
  25. go _goFuncN(c1, c2)
  26. c1 = c2
  27. }
  28. return c1
  29. }
  30. func main() {
  31. c := IterDepth(2)
  32. for i := range c {
  33. fmt.Println(i)
  34. }
  35. }

你可以使用以下代码进行测试:

  1. func main() {
  2. c := IterDepth(2)
  3. for i := range c {
  4. fmt.Println(i)
  5. }
  6. }
英文:

I don't know if it is possible to avoid nested loops, but one solution is to use a pipeline of channels. For example:

  1. const ITER_N = 60
  2. // ----------------
  3. func _goFunc1(out chan string) {
  4. for i := 1; i &lt; ITER_N; i++ {
  5. out &lt;- fmt.Sprintf(&quot;%d&quot;, i)
  6. }
  7. close(out)
  8. }
  9. func _goFuncN(in chan string, out chan string) {
  10. for j := range in {
  11. for i := 1; i &lt; ITER_N; i++ {
  12. out &lt;- fmt.Sprintf(&quot;%s,%d&quot;, j, i)
  13. }
  14. }
  15. close(out)
  16. }
  17. // ----------------
  18. // create the pipeline
  19. func IterDepth(d int) chan string {
  20. c1 := make(chan string)
  21. go _goFunc1(c1)
  22. var c2 chan string
  23. for ; d &gt; 1; d-- {
  24. c2 = make(chan string)
  25. go _goFuncN(c1, c2)
  26. c1 = c2
  27. }
  28. return c1
  29. }

You can test it with:

  1. func main() {
  2. c := IterDepth(2)
  3. for i := range c {
  4. fmt.Println(i)
  5. }
  6. }

答案2

得分: 1

我通常使用闭包来实现迭代器。多个维度并不会使问题变得更加困难。以下是一个示例,展示如何实现迭代器:

  1. package main
  2. import "fmt"
  3. func iter(min, max, depth int) func() ([]int, bool) {
  4. s := make([]int, depth)
  5. for i := range s {
  6. s[i] = min
  7. }
  8. s[0] = min - 1
  9. return func() ([]int, bool) {
  10. s[0]++
  11. for i := 0; i < depth-1; i++ {
  12. if s[i] >= max {
  13. s[i] = min
  14. s[i+1]++
  15. }
  16. }
  17. if s[depth-1] >= max {
  18. return nil, false
  19. }
  20. return s, true
  21. }
  22. }
  23. func main() {
  24. // 三个维度,范围在[1,4)
  25. i := iter(1, 4, 3)
  26. for s, ok := i(); ok; s, ok = i() {
  27. fmt.Println(s)
  28. }
  29. }

你可以在Playground上尝试运行它。

例如,如果需要的话,可以简单地将参数作为一个整数切片传递,这样你就可以为每个维度设置不同的限制。

英文:

I usually implement iterators using closures. Multiple dimensions don't make the problem much harder. Here's one example of how to do this:

  1. package main
  2. import &quot;fmt&quot;
  3. func iter(min, max, depth int) func() ([]int, bool) {
  4. s := make([]int, depth)
  5. for i := range s {
  6. s[i] = min
  7. }
  8. s[0] = min - 1
  9. return func() ([]int, bool) {
  10. s[0]++
  11. for i := 0; i &lt; depth-1; i++ {
  12. if s[i] &gt;= max {
  13. s[i] = min
  14. s[i+1]++
  15. }
  16. }
  17. if s[depth-1] &gt;= max {
  18. return nil, false
  19. }
  20. return s, true
  21. }
  22. }
  23. func main() {
  24. // Three dimensions, ranging between [1,4)
  25. i := iter(1, 4, 3)
  26. for s, ok := i(); ok; s, ok = i() {
  27. fmt.Println(s)
  28. }
  29. }

Try it out on the Playground.

It'd be a simple change for example to give arguments as a single int slice instead, so that you could have per-dimension limits, if such a thing were necessary.

huangapple
  • 本文由 发表于 2016年2月22日 15:27:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/35547964.html
匿名

发表评论

匿名网友

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

确定