How to iterate through two general lists with different types of objects in java?

I want to create an iterator class that allows me to iterate over lists using common types (e.g. lst1 integer, lst2 string) one element after another. For this, I must consider the following situation.

An interface is a common Iterator. This part of the code cannot be changed.

interface Iterator<E> { E next (); boolean hasNext(); } 

The list class is also defined as follows. Most importantly, a list object can return an iterator object using the getIterator () method. This part of the code cannot be changed.

 class List<T> { class ListNode { T val; ListNode next; ListNode (T v) { val = v; next = null; } } ListNode head; List (ListNode hd) { head = hd; } List () { this(null); } void prepend (T val) { ListNode p = new ListNode(val); p.next = head; head = p; } //some other methods class ListIterator implements Iterator<T> { ListNode pos; ListIterator () { pos = head; } public T next () { T res = pos.val; pos = pos.next; return res; } public boolean hasNext () { return pos != null; } } Iterator<T> getIterator () { return this.new ListIterator(); } } 

Suppose both lists are of the same type and now they have the same length. I tried to create a class with two iterator objects and used the methods of the iterator objects to implement the Iterator interface. This part of the code is created by me and can be changed.

 class ZipIterator<T> implements Iterator<T> { int counter; Iterator<T> first; Iterator<T> second; ZipIterator (Iterator<T> f, Iterator<T> s) { first = f; second = s; counter = 0; } public T next () { if (counter % 2 == 0) { counter++; return first.next(); } else { counter++; return second.next(); } } public boolean hasNext () { if (counter % 2 == 0) return first.hasNext(); else return second.hasNext(); } } 

This works fine for two lists with the same type. Here is the code and the result that I used for the test:

 class IteratorUtils { public static void main (String[] args) { List<Integer> lst1 = new List<>(); List<Integer> lst2 = new List<>(); lst1.prepend(3); lst1.prepend(2); lst1.prepend(1); lst2.prepend(8); lst2.prepend(9); lst2.prepend(10); Iterator<Integer> it1 = lst1.getIterator(); Iterator<Integer> it2 = lst2.getIterator(); ZipIterator<Integer> zit = new ZipIterator<>(it1, it2); while (zit.hasNext()) { System.out.println(zit.next()); } } } 

Output:

 1 10 2 9 3 8 

Now I want to implement ZipIterator in a general way, so I can use two lists with different types of elements (for example, integer and string). I know that I need to change the ZipIterator class, so the next () method returns a generic type, but I don't know how to do it. This is the university’s task that I have to do, and the professor left a prompt “to use such wild cards as:? Extends T,? Super T,? Extends Object”. But with wildcards, I can only specify types in or against the direction of inheritance, right? Is it possible to change the ZipIterator class so that it accepts two iterator objects with different types?

+6
source share
4 answers

I will not offer a complete solution (and judging by your efforts, you do not want this), but I will try to explain so that you yourself find it.

First of all, an unrelated note: you specify a specific iteration order. I assume this is normal and I will not touch it.

Your professor has given you a hint about using limited generics. Make it clear why they are needed (see also the textbook here and / or here ). If you were asked to write one method that takes an argument from either of two unknown types, your solution should be to find and take your general superclass - Object .

In generics, the situation is similar - find the most common denominator, only the syntax is a little more complicated. If you should have written a constructor

 ZipIterator(Iterator<Object> f, Iterator<Object> s) {...} 

and try to initialize

 List<Integer> lst1 = new List<>(); List<String> lst2 = new List<>(); new ZipIterator(it1, it2); 

you will get a compilation error (read it). This is because List<String> not List<Object> , although a String is Object . The right way to do this is

 ZipIterator(Iterator<? extends Object> f, Iterator<? extends Object> s) {...} 

where ? extends Object ? extends Object means "any type that extends Object " (this is all because Object ...).

So, you have a constructor, and you will need to make changes to your class in order to adapt it. You do not even need to implement this Iterator<E> , you just keep 2 of those that you are already doing. Finally, the class itself should not have a common type: since its next method should be able to return any type, it always returns Object .

If you have any questions during your future attempts at this problem or if you find that this solution does not meet the requirements for assignment, feel free to leave comments.

+3
source

I know that I need to change the ZipIterator class, so the next () method returns a generic type, but I don't know how to do it.

This is not entirely correct. Since ZipIterator<T> extends Iterator<T> , it actually sets in stone that its next() method should return T And that makes sense: the whole point of the iterator type parameter allows you to specify the type returned by its next() method.

Instead, all your professor wants is the ability to build a ZipIterator<...> from two iterators with different type arguments. For example, he wants to write:

 List<Integer> listOfIntegers = ...; List<String> listOfStrings = ...; ZipIterator<Object> zipIterator = new ZipIterator<>(listOfIntegers.getIterator(), listOfStrings.getIterator()); 

Note that since zipIterator.next() will sometimes return Integer , and sometimes String , we needed something like ZipIterator<Object> , which allows both. Other options included ZipIterator<Serializable> or ZipIterator<Comparable<?>> , since Integer -s and String -s are both Serializable and both Comparable<?> .


So the problem that your professor wants to solve is that in your current code, your constructor requires that iterators have the same type argument (both for each other and for ZipIterator itself):

 ZipIterator (Iterator<T> f, Iterator<T> s) 

Do you see how to fix it?

0
source

since I understand that you want to iterate over a list of different types, one solution is for your constructor to accept an iterator by fulfilling the requirement that it is an iterator of any thing that extends the object, but this will limit your use of the extracted elements to use it as objects or you will have to give them away to achieve further tasks, and a less restrictive approach is to make the accepted constructor an iterator to fulfill the requirement that it be an iterator of any thing that distributes lizhayshego common ancestor as the ZipIterator(Iterator<? extends T> f, Iterator<? extends T> s) , so your class will look like this

 class ZipIterator<T> implements Iterator<T> { int counter; Iterator<? extends T> first; Iterator<? extends T> second; ZipIterator(Iterator<? extends T> f, Iterator<? extends T> s) { first = f; second = s; counter = 0; } @Override public T next() { if (counter % 2 == 0) { counter++; return first.next(); } else { counter++; return second.next(); } } @Override public boolean hasNext() { if (counter % 2 == 0) { return first.hasNext(); } else { return second.hasNext(); } } } 

then to use it you can specify the best suitable superclass with which both types converge, in the case of its Object you can write ZipIterator<Object> zit = , the following code will show you an arbitrary use case

  List<StringBuilder> bl= Arrays.asList(new StringBuilder("hi i'm builder")); List<String> sl = Arrays.asList("hi i'm string"); ZipIterator<CharSequence> zit = new ZipIterator<>(bl.iterator(), sl.iterator()); while (zit.hasNext()) { CharSequence cs = zit.next(); System.out.println(cs.subSequence(6,cs.length())); } 
0
source

Thanks for the help. I learned a lot. Here is my solution and a few more explanations for this task.

First of all, note that the design of the ZipIterator class is not set as a stone. ZipIterator was developed by me. It may be a different solution, but it was my attempt.

To indicate the task: “Please create an IteratorUtils class in several ways. The zip method gets two iterator objects and returns one iterator object that iterates through the elements of two received iterator objects. The iterator returned by the zip function should stop after the last element of the shorter iterator object. Use wildcards so you can apply the zip function to different types of iterator objects. "

To do this, I first created the IteratorUtils class. Please note that the zip function design is also not set in stone. In the task, he only says: "The zip method receives two iterator objects and returns one iterator object, which iterations alternate through the elements of two received iterator objects."

 class IteratorUtils { static ZipIterator zip (Iterator<? extends Object> first, Iterator<? extends Object> second) { return new ZipIterator(first, second); } } 

Then I created the ZipIterator class. After reading your answers and some lessons, I understood the meaning of parameters of a limited type in this task. Like user1803551, the ZipIterator class should not be shared. I just needed to understand that I want to find a common superclass (here Object). So I had to change the ZipIterator class to the following:

 class ZipIterator { int counter; Iterator first; Iterator second; ZipIterator (Iterator<? extends Object> f, Iterator<? extends Object> s) { first = f; second = s; counter = 0; } public Object next () { if (counter % 2 == 0) { counter++; return first.next(); } else { counter++; return second.next(); } } public boolean hasNext () { if (counter % 2 == 0) return first.hasNext(); else return second.hasNext(); } } 

In my main method, I use the following code:

 public static void main (String[] args) { List<Integer> lst1 = new List<>(); List<String> lst2 = new List<>(); lst1.prepend(3); lst1.prepend(2); lst1.prepend(1); lst2.prepend("three"); lst2.prepend("two"); lst2.prepend("one"); Iterator<Integer> it1 = lst1.getIterator(); Iterator<String> it2 = lst2.getIterator(); ZipIterator zit = zip(it1, it2); while (zit.hasNext()) { System.out.println(zit.next()); } } 

Output:

 1 one 2 two 3 three 
0
source

All Articles