views:

153

answers:

6

Suppose I have this:

public class Unit<MobileSuit, Pilot> {

    ...

    List<MobileSuit> mobileSuits;
    List<Pilot> pilots;

    ...
}

And I would like to iterate through the pair of each in the simplest way outside of that class. How should I go about doing that? I thought about doing this:

public class Unit<MobileSuit, Pilot> {

    ...
    Iterator<MobileSuit> iteratinMechas;
    Iterator<Pilot> iteratinPeople;

    class IteratorCustom<MobileSuit, Pilot> implements Iterator {

        public boolean hasNext() {
            return iteratinMechas.hasNext() && iteratinPeople.hasNext();
        }

        public void remove() {
            iteratinMechas.remove();
            iteratinPeople.remove();
        }

        public Object next() {
            // /!\
        }

    }

    public Iterator iterator() {
        return new IteratorCustom<MobileSuit, Pilot>(mobileSuits, pilots);
    }
}

Something along those lines.

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?

Also, I can't make a new class to combine MobileSuit and Pilot. I need to keep them separate, even though I'm iterating through both at a time. The reason is that there might be Mobile Suits that have no pilots, and I'm not sure how to fix that by keeping them at the same class. This class needs to be processed in other places, so I'd have to unify a interface around that and a lot of other stuff. Basically, assume MobileSuit and Pilot need to be separated.

+2  A: 

The reason is that there might be Mobile Suits that have no pilots, and I'm not sure how to fix that by keeping them at the same class.

You can use null values, right? Which is the correct way of doing it - have each suit keep track of its pilot. If it has no pilot, then indicate that with a null value there.

But, if you're dead set on not doing that for some reason...

public class SuitAndPilot
{
    public MobileSuit suit;
    public Pilot pilot;

    public SuitAndPilot(Suit s, Pilot p) {
           suit = s;
           pilot = p;
    }
}
Anon.
+1  A: 

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.

Jon Skeet
Even better, though the Pair class could be strange in the overall Object Model it certainly makes a good utility class for this problem.
Newtopian
+1  A: 

Why not have a class MannedMobileSuit as a subclass of MobileSuit that contains an instance of a pilot ? That would solve your problem by having a getPilot method.

Usually when you get such problems (needing to return two instances) it is because your Object model is not appropriate and should be changed. Keep your options open

Newtopian
Hmm, I'll try that and see how it goes.
Setsuna F. Seiei
+3  A: 

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> {
        return new Pair<T1, T2>(it1.next(), it1.next());
    }

    ...

}
Stephen C
A: 

You could just use a Map<MobileSuit, Pilot>, where a null value mapped to a MobileSuit indicates no pilot. The Iterator could just be an Iterator<Map.Entry<MobileSuit, Pilot>> retrieved by map.entrySet().iterator().

ColinD
Care to explain the downvote?
ColinD
How do you fill the Map?Do you mean replace the two lists with a Map? You could use map.keySet() and map.values() if the raw lists are needed, but then we lose ordering.
pydave
Yes, I meant to replace the two lists with a Map. It seems clear that what's needed here is associations between MobileSuits and Pilots and that's exactly what a Map is for. Now, if there could be Pilots without a MobileSuit as well as the other way around, it might make sense to maintain the lists as well (sets would probably better) while still using a map for associating the two.
ColinD
A: 

Isn't that enough ?

for(MobileSuit ms : MobileSuits) {
    for(Pilot p : pilots){
        //TODO
    }
}
Aymen
That's O(n²) instead of O(n).
Setsuna F. Seiei