What's the difference between a iterator = null and hasnext = false?

534 views Asked by At

I am writing a code to flatten a 2d list, like [[1,2], [3], [4,5,6]]. I want them to be in one list like [1,2,3,4,5,6]. when i want to check if coliter is at the end of a one row, i want them to change to the next row.

while ((colIter == null || !colIter.hasNext()) && rowIter.hasNext())

When i am doing this, i am thinking about what's the difference between colIter == null and !colIter.hasNext()?

private Iterator<List<Integer>> rowIter;
private Iterator<Integer> colIter;

public Solution_2(List<List<Integer>> vec2d) {
    rowIter = vec2d.iterator();
    colIter = Collections.emptyIterator();
}

@Override
public Integer next() {
    return colIter.next();
}

@Override
public boolean hasNext() {
    while ((colIter == null || !colIter.hasNext()) && rowIter.hasNext()) {
        colIter = rowIter.next().iterator();
    }
    return colIter != null && colIter.hasNext();
}

@Override
public void remove() {
    while (colIter == null && rowIter.hasNext()) {
        colIter = rowIter.next().iterator();
        if (colIter != null) {
            colIter.remove();
        }
    }
}
2

There are 2 answers

1
Makoto On BEST ANSWER

If you take your nested list...

[ [1,2], [3], [4,5,6] ]

...you could think of it in a different fashion.

0: [1, 2]
1: [3]
2: [4, 5, 6]

That is to say, you have a two-dimensional representation of your list because of its nested property. Row 0 contains the values 1 and 2, row 1 contains 3, and row 2 contains 4, 5, and 6.

When you write

colIter == null || !colIter.hasNext()) && rowIter.hasNext()

What you're checking for is this:

  • Is there a column?
  • If there is,
    • Have we exhausted the column iteration AND do we have more things to read from our rows?

Consider a nested list in this fashion:

0: [1, 2]
1: []
2: [3, 4, 5]

For Row 1, there definitely is a column, but we don't have any values to process and there's something else to do, so we can move past this record.

If we're at the end of the nested list, then I would expect a call to colIter.next() to throw a NoSuchElementException instead of returning null. You may want to look into that.

2
Nikolas Charalambidis On

Q: I am writing a code to flatten a 2d list, like [[1,2], [3], [4,5,6]. I want them to be in one list like [1,2,3,4,5,6].

A: For sake of brevity, use the feature Stream::flatMap which flattens the structure:

List<Integer> list = vec2d.stream().flatMap(List::stream).collect(Collectors.toList());

Prior to version, there is enough the for-each usage for this issue.

Q: ... what's the difference between colIter == null and !colIter.hasNext()?

A: The colIter == null checks whether the Iterator itself is null or not. By default, returning an iterator from any existing collection never results in a null alike Iterator.

colIter.hasNext() is a method called from the Iterator which according to its documentation returns true if the iteration has more elements that implies that the subsequent call of Iterator::next will return an element and will not throw NoSuchElementException.