Amir Rachum
Amir Rachum

Reputation: 79635

iterator over nested collections

I have two data structures in Java:
One is called DebateAssignment and has 5 DebateTeam objects, each associated with a specific enum that includes

{JUDGE, PROP1, PROP2, OP1, OP2}

In another class I use List<DebateAssignment> and I want to create an iterator that will point to a specific DebateTeam in a specific DebateAssignment and I want it to iterate over all teams over all assignments, going from an assignment to assignment seamlessly.

How would I go about doing that?

Upvotes: 4

Views: 2760

Answers (4)

Kevin Bourrillion
Kevin Bourrillion

Reputation: 40851

One way, using google-collections / guava:

return Iterables.concat(Iterables.transform(assignments,
    new Function<DebateAssigment, Collection<DebateTeam>>() {
      public Collection<DebateTeam> apply(DebateAssignment assignment) {
        return assignment.getDebateTeams();
      }
    }));

Another way is to store the data as a Multimap<DebateAssignment, DebateTeam>, then simply iterate over either the values() or entries() view. That data structure won't model the JUDGE/PROP1/etc. association, though.

Upvotes: 5

meriton
meriton

Reputation: 70564

Probably the easiest approach is:

List<DebateAssignment> list = ...
List<DebateTeam> dtList = new ArrayList<DebateTeam>();
for (DebateAssignment da : list) {
    dtList.addAll(da.getTeams());
}
return dtList.iterator();

Of course you could write a new class that implements Iterator<DebateTeam> that "flattens" nested iterators, but that is somewhat involved, as you will have to explicitly keep track of both iterators ... (see Clinton's answer for details on this).

Upvotes: 2

Clinton
Clinton

Reputation: 2837

Assuming DebateAssignment has something like

public Collection<DebateTeam> getDebateTeams();

You want an Iterator<DebateTeam>?

If so, would you want something like:

public class DebateTeamIterator implements Iterator<DebateTeam> {
    private Iterator<DebateAssignment> iAssignment;
    private Iterator<DebateTeam> iTeam;

    public DebateTeamIterator(Iterator<DebateTeam> iAssignment) {
        this.iAssignment = iAssignment;
        if (iAssignment.hasNext())
            iTeam = iAssignment.next().getDebateTeams().iterator();
        else
            iTeam = new LinkedList<DebateTeam>().iterator();
    }

    public boolean hasNext() {
       return iTeam.hasNext() || iAssignment.hasNext();
    }

    public DebateTeam next() {
        if (!iTeam.hasNext())
            iTeam = iAssignment.next().getDebateTeams().iterator();
        return iTeam.next();
    }

    // ... other methods removed for brevity...
}

Upvotes: 4

Chandra Sekar
Chandra Sekar

Reputation: 10843

You can extend a list implementation like ArrayList and add a method to return an Iterator implementation which does what you want.

Overriding the iterator() method may not be an option doe to the generic type of the iterator returned by it.

Upvotes: 0

Related Questions