Suppose I have this:
public class Unit {
...
List mobileSuits;
List pilots;
...
}
Also, I can't make a new class to combine MobileSuit and Pilot.
That doesn't sound correct. It sounds like you can't replace MobileSuit and Pilot by a single class, but I don't see any reason why you can't have a single class that combines them - i.e. one which just has a getPilot()
method and a getMobileSuit()
method. You could use a generic Pair
class for the same purpose, but a custom class would be easier to use.
On the other hand, if you want to do this sort of "zipping" operation in multiple places, it might be one solution. Alternatively, you could write a generic interface to represent the act of combining the two distinct items - which could return a SuitedPilot
or whatever your combination class is.
Came across this page trying to solve this issue, and turns out that there's a library out there that's already solved it using Java 8 streams (check out the Zip function).
You can convert a list to a stream just by calling list.stream()
https://github.com/poetix/protonpack
Stream<String> streamA = Stream.of("A", "B", "C");
Stream<String> streamB = Stream.of("Apple", "Banana", "Carrot", "Doughnut");
List<String> zipped = StreamUtils.zip(streamA,
streamB,
(a, b) -> a + " is for " + b)
.collect(Collectors.toList());
assertThat(zipped,
contains("A is for Apple", "B is for Banana", "C is for Carrot"));
Anyway, the problem is that I can't really return just a single object from next(), and I also can't have a Iterator take more than one type. So, any thoughts?
Obviously you are going to need a light-weight "pair" class. This is roughly analogous to the Map.Entry
inner class.
Here's a rough cut at a generic solution:
public class ParallelIterator <T1, T2> implements Iterator<Pair<T1, T2>> {
public class Pair<TT1, TT2> {
private final TT1 v1;
private final TT2 v2;
private Pair(TT1 v1, TT2 v2) { this.v1 = v1; this.v2 = v2; }
...
}
private final Iterator<T1> it1;
private final Iterator<T2> it2;
public ParallelIterator(Iterator<T1> it1, Iterator<T2> it2) {
this.it1 = it1; this.it2 = it2;
}
public boolean hasNext() { return it1.hasNext() && it2.hasNext(); }
public Pair<T1, T2> next() {
return new Pair<T1, T2>(it1.next(), it2.next());
}
...
}
Note: this doesn't explicitly deal with cases where the lists have different lengths. What will happen is that extra elements at the end of the longer list will be silently ignored.
Improving on the answer by user2224844
, here is a simple version that will try no to run into an exception:
final Iterator<String> pilotIterator = pilots.iterator();
mobileSuits.forEach(m -> {
Pilot p = pilotIterator.hasNext()? pilotIterator.next():nullOrWahtever;
<Now do your work with m and p variables>
...
});
Isn't that enough ?
for(MobileSuit ms : MobileSuits) {
for(Pilot p : pilots){
//TODO
}
}