【问题标题】:Iterator returns wrong integer values迭代器返回错误的整数值
【发布时间】:2014-04-29 22:45:45
【问题描述】:

我必须实现类Incrementer,它假设实现Iterable

输出应该是:

1 2 3 4 5 6 7 8 9 10 
1 3 5 7 9 
10 9 8 7 6 5 4 3 2 1 
10 9 8 7 6 5 4 3 2 1 
1 2 3 4 6 8 10 
1 2 3 4 5 6 7 8 6 4 2 
10 9 8 7 6 5 6 7 8 9 10

我明白了:

2 3 4 5 6 7 8 9 10 
3 5 7 9 11 
9 8 7 6 5 4 3 2 1 

2 3 4 6 8 10 
2 3 4 5 6 7 8 
9 8 7 6 5 6 7 8 9 10 

我的Incrementer 班级看起来像这样:

    package in;

import java.util.Iterator;

public class Incrementer implements Iterable<Integer> {
    int val, step, a, b;

    private Incrementer(int a, int b, int step) {
        this.step = step;
        this.a = a;
        this.b = b;
        if (step > 0)
            val = a;
        else
            val = b;
    }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {

            @Override
            public boolean hasNext() {
                if (step < 0 && val > a)
                    return true;
                else if (step > 0 && val < b)
                    return true;
                return false;
            }

            @Override
            public Integer next() {
                return val += step;
            }

            @Override
            public void remove() {
            }
        };
    }

    public static Incrementer in(int a, int b) {
        ///tu zmieniamy tresc dla ostatniego przypadku

        if (a < b)
            return new Incrementer(a, b, 1);
        else
            return new Incrementer(b, a, -1);
    }

    public Incrementer by(int step) {
        this.step = step;
        if (this.step < 0 && this.a < this.b || this.step > 0 && this.a > this.b) {
            int tmp = this.a;
            this.a = this.b;
            this.b = tmp;
        }
        return this;
    }

}

和测试代码:

package in;
import static in.Incrementer.*;

public class Test {

  public static void main(String[] args) {

    for(int k : in(1, 10)) System.out.print(k + " ");
    System.out.println();


    for(int k : in(1, 10).by(2)) System.out.print(k + " ");
    System.out.println();

    for(int k : in(10, 1)) System.out.print(k + " ");
    System.out.println();

    for(int k : in(1, 10).by(-1)) System.out.print(k + " ");
    System.out.println();

    Incrementer inc;
    for (int i : inc = in(1,10) ) {
      if (i == 4) inc.by(2);
      System.out.print(i + " ");
    }
    System.out.println();
    for (int i : inc = in(1,10) ) {
      if (i == 8) inc.by(-2);
      System.out.print(i + " ");
    }
    System.out.println();
    for(int k : inc = in(10, 1)) {
      if (k == 5) inc.by(1);
      System.out.print(k + " ");
    }

  }


}

我不知道我在哪里做错了。

【问题讨论】:

    标签: java iterator integer iterable


    【解决方案1】:

    错误是你没有初始化val,所以会从0(默认值)开始。

    在您的第二个示例中,您将使用return val += step;val = 0step = 2,因此它将从 2 开始并从那里继续。

    在您的第三个示例中,a = 10b = 1step = -1val = 0,因此您不会进入

    if (step < 0 && val > a)
    

    因为val &lt; a,而你不会进入

    else if (step > 0 && val < b)
    

    因为step &lt; 0

    编辑:

    在编辑后的帖子中,你应该修改next()方法返回val,并且只在后面增加它:

    @Override
    public Integer next() {
        int ret = val;
        val += step;
        return val;
    }
    

    你还应该修改hasNext()中的条件:

    @Override
    public boolean hasNext() {
        if (step < 0 && val >= a)
            return true;
        else if (step > 0 && val <= b)
            return true;
        return false;
    }
    

    为了使您进行第四次测试工作,您必须将by() 方法更改为反转ab(如果需要):

    public Incrementer by(int step) {
        if ((this.step<0)!=(step<0) && this.val==this.a)
            this.val = this.b;
        else if ((this.step<0)!=(step<0) && this.val==this.b) 
            this.val = this.a;
        else if (this.val!=this.a && this.val!=this.b) {
            this.val -= this.step;
            this.val += step;
        }
        this.step = step;
    
        return this;
    }
    

    你也可以测试反例:

    for(int k : in(10, 1).by(1)) System.out.print(k + " ");
    

    完整代码如下:

    public class Incrementer implements Iterable<Integer> {
        int val, step, a, b;
    
        private Incrementer(int a, int b, int step) {
            this.step = step;
            this.a = a;
            this.b = b;
            if (step > 0)
                val = a;
            else
                val = b;
        }
    
        @Override
        public Iterator<Integer> iterator() {
            return new Iterator<Integer>() {
    
                @Override
                public boolean hasNext() {
                    if (step < 0 && val >= a)
                        return true;
                    else if (step > 0 && val <= b)
                        return true;
                    return false;
                }
    
                @Override
                public Integer next() {
                    int ret = val;
                    val += step;
                    return ret;
                }
    
                @Override
                public void remove() {
                }
            };
        }
    
        public static Incrementer in(int a, int b) {
            ///tu zmieniamy tresc dla ostatniego przypadku
    
            if (a < b)
                return new Incrementer(a, b, 1);
            else
                return new Incrementer(b, a, -1);
        }
    
        public Incrementer by(int step) {
            if ((this.step<0)!=(step<0) && this.val==this.a)
                this.val = this.b;
            else if ((this.step<0)!=(step<0) && this.val==this.b)
                this.val = this.a;
            else if (this.val!=this.a && this.val!=this.b) {
                this.val -= this.step;
                this.val += step;
            }
            this.step = step;
    
            return this;
        }
    
    }
    

    【讨论】:

    • 谢谢我编辑了 OP。请看一下。再次感谢您。
    • 谢谢我再次编辑代码,就像你说的。但不幸的是,输出与原始帖子中发布的相同。请看一下。哦,操作已编辑
    • @Yoda 编辑了我的答案。
    【解决方案2】:

    你一开始就犯了一个根本性错误:Iterable 应该能够发出无限多个 Iterators,但你只能发出一个。

    每个Iterator 都应该有足够的内部状态,以便能够迭代您的值集。

    要同时解决这个问题和其他问题,请将iterator() 中的代码更改为此:

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            int val = a; // <-- HERE
    

    并将您的 .next() 更改为:

    public Integer next()
    {
        int ret = val;
        val += step;
        return ret;
    }
    

    并删除您的其他val

    (另外,我建议您将 a 重命名为 startb 重命名为 end


    最后一句话:为了完全遵守Iterator的合同,你的.remove()应该这样做:

    public void remove()
    {
        throw new UnsupportedOperationException();
    }
    

    不,您不需要声明该方法会引发此异常,因为它是一个未经检查的异常。请参阅 RuntimeException 的 javadoc。

    【讨论】:

    • 我应该如何将start endstep 设置为迭代器。我不知道如何通过方法by() 访问它。示例 in(1, 10).by(-1) start 应设置为 1,end 应设置为 10,step tp -1。
    • 嗯...这是你锻炼的要求吗?您不应该能够在迭代器运行时修改它的行为...
    • 是的,很不幸。在练习中老师写道:// W trakcie iteracji można zmieniac krok 这意味着在迭代时您可以更改步骤。但这是非常糟糕的老师(不是我的老师)。
    • 哦,天哪...一位老师要求故意违约:/
    猜你喜欢
    • 2021-11-02
    • 2012-12-23
    • 1970-01-01
    • 1970-01-01
    • 2018-03-15
    • 2023-01-22
    • 2011-07-22
    • 2019-02-12
    • 1970-01-01
    相关资源
    最近更新 更多