26801

Iterator returns wrong integer values

Question:

I have to implement class Incrementer and it suppose to implement Iterable.

<strong>The output should be:</strong>

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

<strong>I do get:</strong>

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

My Incrementer class looks like that:

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; } }

and the Testcode:

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 + " "); } } }

I do not know where I did mistake.

Answer1:

The mistake is that you doesn't initialize val, so it will start at 0 (the default value).

In your second example, you will return val += step;, with val = 0 and step = 2, so it will start at 2 and continue from there.

In your third example, a = 10, b = 1, step = -1 and val = 0, so you will not enter in

if (step < 0 && val > a)

because val < a, and you will not enter in

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

because step < 0.

<strong>EDIT:</strong>

In the edited post, you should modify the next() method to return val, and only increase it after :

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

You should also modify the conditions in the hasNext():

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

To make you fourth test work, you will have to change the by() method to invert a and b if needed:

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; }

You can also test the inverse case:

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

Here is the complete code:

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; } }

Answer2:

You make one fundamental mistake to begin with: an Iterable is supposed to be able to issue infinitely many Iterators, but you can only issue one.

Each Iterator should have sufficient internal state so that it can be able to iterate over your set of values.

To fix this and your other problem at the same time, change your code to this in iterator():

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

and change your .next() to:

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

and remove your other val.

(also, I'd suggest you rename a to start and b to end)

<hr />

Final remark: in order to fully obey the contract of Iterator, your .remove() should do that:

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

And no, you don't need to declare that the method throws this exception since it is an <em>unchecked</em> exception. See javadoc for RuntimeException.

Recommend

  • Using G++ to compile multiple *.cpp and *.h files in Sublime 2
  • Bundling shell commands in NodeJs spawn
  • How to Get DB Field name from ConstraintViolationException - Hibernamte
  • Cythonized function unexpectedly slow
  • Passing parameter through “window.location.href”
  • Select options in sencha touch is not working for android
  • Django invalid literal for int() with base 10
  • ListItem.Attributes.Add not working
  • Diff between two dataframes in pandas
  • Should I or shouldn't I use the CachingConnectionFactory with hornetq 2.4.1
  • WPF - CanExecute dosn't fire when raising Commands from a UserControl
  • How to use RequestBodyAdvice
  • Jetty Server not starting: Unable to establish loopback connection
  • Body moving without any force applied? (Box2d)
  • Paperclip, set path outside of rails root folder
  • does jqgrid support a multiple checkbox list for editing
  • java.lang.NoClassDefFoundError: com.parse.Parse$Configuration$Builder on below Lollipop versions
  • JFileChooser in front of fullscreen Swing application
  • jQuery show() function is not executed in Safari if submit handler returns true
  • Align navbar back button on right side
  • HTML download movie download link
  • Modifying destination and filename of gulp-svg-sprite
  • Shallow update not allowed (git > 1.9)
  • How to handle AllServersUnavailable Exception
  • How to model a transition system with SPIN
  • VBA Convert delimiter text file to Excel
  • ORA-29908: missing primary invocation for ancillary operator
  • How to disable jQuery.jplayer autoplay?
  • How to stop GridView from loading again when I press back button?
  • Bitwise OR returns boolean when one of operands is nil
  • EntityFramework adding new object to nested object collection
  • sending mail using smtp is too slow
  • Checking variable from a different class in C#
  • Busy indicator not showing up in wpf window [duplicate]
  • costura.fody for a dll that references another dll
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • Binding checkboxes to object values in AngularJs
  • How can I use `wmic` in a Windows PE script?
  • failed to connect to specific WiFi in android programmatically
  • How can I use threading to 'tick' a timer to be accessed by other threads?