# Problem 3: Row-by-Row Iterator (10 points) Given a two-dimensional structure (example below), a row-by-row iterator (aka. natural Pusheen walker) yields elements from the first row from left to right, then proceed to the second row, so on so forth. As an example, the 2d structure on the left results in the sequence on the right. Observe that the empty rows—which can appear anywhere, including at the start and/or the end—are skipped. ![Screenshot 2024-02-15 at 7.18.55 AM](https://hackmd.io/_uploads/Skcn_R9ip.png) You will implement a public class: ```java public class PusheenWalker<T> implements Iterable<T> { ... } ``` with the following specifications: - The only constructor takes as input a List<List<T>> representing the said 2D structure. As an example, this lets us write new PusheenWalker<>(twoD) and the result has type PusheenWalker<Integer>. - The iterator given by this class—as described earlier—yields elements from left to right, then onto the following row, skipping each empty row, until all the elements have been returned. There may be many consecutive empty rows. **Ground Rules:** Your code cannot store a collection of any kind, aside from a reference to the input structure. This means, for example, that you cannot make an output list ahead of time and simply return from that list. Moreover, do not use Java streams. Grading: Assignment summed up: - we need to figure out the underlying datastructure that we want to iterate over. - figure out how we get `hasNext()` and `next()`. ```java import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; public class PusheenWalker<T> implements Iterable<T> { private final List<List<T>> twoD; public PusheenWalker(List<List<T>> twoD) { this.twoD = twoD; } @Override public Iterator<T> iterator() { return new Iterator<T>() { private int rowIndex = 0; // To keep track of the current row private int colIndex = 0; // To keep track of the current column within the row @Override public boolean hasNext() { // Move forward to find a non-empty row if necessary while (rowIndex < twoD.size() && (twoD.get(rowIndex) == null || twoD.get(rowIndex).isEmpty() || colIndex >= twoD.get(rowIndex).size())) { rowIndex++; colIndex = 0; // Reset column index at the start of a new row } return rowIndex < twoD.size(); // Check if there are more rows to iterate } @Override public T next() { if (!hasNext()) { // Uses hasNext to ensure there's a next element throw new NoSuchElementException("No more elements to iterate"); } T nextItem = twoD.get(rowIndex).get(colIndex++); // Check if we need to move to the next row for subsequent calls if (colIndex >= twoD.get(rowIndex).size()) { rowIndex++; colIndex = 0; } return nextItem; } }; } } ``` in out `main` we can then use this for-each loop: ```java List<List<Integer>> twoD = List.of( List.of(3, 7), List.of(), List.of(1), List.of(5, 0, 2) ); PusheenWalker<Integer> walker = new PusheenWalker<>(twoD); // our code allows this iteration to happen for (Integer item : walker) { System.out.println(item); } ``` # Problem 3: Bounded Skipper Iterator (10 points) For integer $k > 1$, the bounded skipper sequence of length n is the sequence of the first n numbers such that each number is neither divisible by k nor has k inside its decimal representation (e.g., $145223$ has $k = 52$ inside). For example, using $k = 3$, the bounded skipper sequence of length `n = 11` is $1, 2, 4, 5, 7, 8, 10, 11, 14, 16, 17$ (Notice that $3, 6, 9, 12, 15$ are skipped because they are divisible by 3, and 13 is skipped because it contains 3.) You will write a public class `public class BoundedSkipper implements Iterable<Integer>` with the constructor `public BoundedSkipper(int k, int n) {...}` so that the following code will work ```java for (int v: new BoundedSkipper(3, 11)) { System.out.println(i); // prints out the above sequence on separate lines } ``` Since the class implements Iterable, it must have a public Iterator<Integer> iterator() method. #### Ground Rules: 1. The only file you can modify here (aside from creating/writing tests) is BoundedSkipper.java. 2. You must not use IntStream, LongStream, or DoubleStream. 3. You must not construct the entire sequence anywhere. It is expected that your iterator generates the next number in the sequence on the fly. This means that you cannot, for example, make an ArrayList of length n and return it. In fact, you cannot store more a constant amount of data anywhere in your class. ```java import java.util.Iterator; import java.util.NoSuchElementException; public class BoundedSkipper implements Iterable<Integer>{ // Instance Variable private final int k; private final int n; // Constructor public BoundedSkipper(int k, int n) { this.k = k; this.n = n; } @Override public Iterator<Integer> iterator() { return new Iterator<Integer>() { private int cur = 0; private int next = 1; @Override public boolean hasNext() { // TODO Auto-generated method stub return cur < n; } @Override public Integer next() { // TODO Auto-generated method stub if (!hasNext()) { throw new NoSuchElementException(); } while (!isValid(next)) { next++; } cur++; return next++; } private boolean isValid(int val) { if (val % k ==0) { return false; } return !String.valueOf(val).contains(String.valueOf(k)); } }; } public static void main(String[] args) { for (int v: new BoundedSkipper(3, 11)) { System.out.println(v); // prints out the above sequence on separate lines } } } ```