Iterator To Flatten It

Published: Jun 15, 2017

Let’s revisit the Iterator pattern. “Iterator” is one of design patterns in object-oriented programming (OOP). Needless to say, extremely famous Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides) are creators. As in the Wikipedia’s Iterator pattern, the iterator pattern is used when traversing container without knowing how the container works. It is OOP’s favorite pattern to “decouple” the iterator from container.

What does that actually mean? The iterator defines two methods, hasNext() and next(). Repeating these two method, I can traverse all elements in the container. For example, Java’s ArrayList are LinkedList examples of the containers. These two have different data structures, but I can traverse all elements exactly the same way: hasNext() and nex().

Since the iterator is a handy feature, many including custom classes provide a way to access their elements by the iterator. Probably, this is a reason I see various iterator implementation problems. The iterator looks a good topic to leave a memo, so I’m going to write about two iterators here. These two will flatten nested structure: 2D vector and nested list.

Problem Description - Flatten 2D Vector

“Implement an iterator to flatten 2D vector” is the problem. It is the iterator, so the implementation should have hasNext() and next() methods. Repeating these two methods, all elements in 2D vector should be traversed. For example, [[1, 2], [3], [4, 5, 6]] is given, the code:


    while (v2DIter.hasNext()) {
        result.add(v2DIter.next());
    }

should add all elements to the result list. When it finishes, the result should be [1, 2, 3, 4, 5, 6].

The idea to implement iterator to flatten 2D vector

This sort of nested something is often solved by iterator of iterators approach. A parent iterator traverses vectors, say [1, 2] or [3]. Child iterators traverse individual elements, say 1, 2, or 3.

The most challenging part is when and how to update the child iterator. Choices are only two: either hasNext() or next() method must be responsible to update. In general, it is reasonable to do in next() method. This is because, updating the itereator changes a current element where the iterator points. This behavior is something unexptected for hasNext(), but reasonable to next() method.

Java code for iterating 2D Vector

Above prints:


1, 2, 3, 4, 5, 6, 

Problem Description - Flatten Nested List

“Implement an iterator to flatten nested list” is the problem. Like previous problem, the iterator implementation should have hasNext() and next() methods. Repeating these two methods, all elements in the nested list should be traversed. For example, [[1, 2], 3, [4, [5, 6]]] is given, the code:


    while (nestedLIter.hasNext()) {
        result.add(nestedLIter.next());
    }

should add all elements to the result list. When it finishes, the result should be [1, 2, 3, 4, 5, 6].

This is similar to flatten 2D vector. Big difference is inside of an outermost list is not always a list. Inner elements may be an integer, list, or nested list. This problem is more complicated compared to the previous one.

To express each element in the nested list, the interface NestedInteger is provided.


    interface NestedInteger {
        boolean isInteger();
        Integer getInteger();
        List<NestedInteger> getList();
    }

The idea to implement iterator to flatten nested list

Here again, this sort of nested something can be solved by iterator of iterators approach. In this case, iterator of iterafor of iterator of … may be there. To keep track the data something like … of … of … of …., a stack would be a good data structure.

If I find the itereator points a list, I will stack it. Then, I will pull out an inner iterator. If the inner iteartor points another list, I will stack it. Then, I will pull out the inner of inner iterator (repeat this as long as needed). At some level, pulled out iterator should point an integer. This is the value to add to the result.

Likewise, the challenging part is when and how to update the iterators. Following the policy, “reasonable to do in next() method, the iterators will be updated in next(). However, in this case, I saved a current integer value to an instance variable. This is because current interator may or may not points a value. It may another itereator. Saving a next value makes easy to update the iterators.

Java code for iterating nested list

Resources

Latest Posts

Vite + Vue + Bun on Rails

Vue.js is one of frontend frameworks gaining popularity among rapidly emerging JavaScript technologies. The combination of Vue.js and Rails is becoming more popular as well, however, Vue.js development on Rails is not so straightforward. The reason would be that Vue.js relies on Vite for a development environment such as HMR (Hot Module Replacement) and bundling.

Bun + React on Rails

In the frontend world, new technologies keep emerging rapidly these years. Still, React is a well-established and very popular frontend framework, Vue.js, Svelte, Astro and more frameworks are gaining popularity. Not just the frameworks, tools for a transpiler/bundler or sort are also under a rapid development. In JavaScript domain, esbuild, rollup, vite and some more are out.

Ruby on Rails Secrets Management

A web application needs various kinds of values, params and etc which should not be revealed to the public, say GitHub repo. For example, API keys, tokens, passwords, and endpoints, all those should be kept secret. Another important factor is that such secrets should be shared among the team members. Additionally, all those secrets should come along with the deployment.