同时提供两个列表内容的迭代器?

2022-09-01 14:41:40

假设我有这个:

public class Unit<MobileSuit, Pilot> {

    ...

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

    ...
}

我想以该类之外最简单的方式迭代每个对。我应该如何去做呢?我想过这样做:

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);
    }
}

沿着这些路线的东西。

无论如何,问题是我不能真正从next()只返回一个对象,我也不能让迭代器采用多个类型。那么,有什么想法吗?

另外,我无法制作一个新类来组合MobileSuit和Pilot。我需要将它们分开,即使我一次迭代两者。原因是可能有没有飞行员的机动战士,我不确定如何通过将它们保持在同一班级来解决这个问题。这个类需要在其他地方处理,所以我必须围绕它和许多其他东西统一一个接口。基本上,假设MobileSuit和Pilot需要分开。


答案 1

无论如何,问题是我不能真正从next()只返回一个对象,我也不能让迭代器采用多个类型。那么,有什么想法吗?

显然,您将需要一个轻量级的“对”类。这大致类似于内部类。Map.Entry

以下是通用解决方案的粗略切割:

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());
    }

    ...

}

注意:这不会明确处理列表具有不同长度的情况。将要发生的事情是,较长列表末尾的额外元素将被默默忽略。


答案 2

这是从Stephen C的答案中复制+编辑的。随意使用:

public class Pair<T1, T2> {
    private final T1 v1;
    private final T2 v2;
    Pair(T1 v1, T2 v2) {
        this.v1 = v1;
        this.v2 = v2;
    }
    public T1 first(){
        return v1;
    }
    public T2 second(){
        return v2;
    }
}

public class ParallelIterator <T1, T2> implements Iterator<Pair<T1, T2>> {

    private final Iterator<T1> it1;
    private final Iterator<T2> it2;

    public ParallelIterator(Iterator<T1> it1, Iterator<T2> it2) { 
        this.it1 = it1; this.it2 = it2;
    }

    @Override
    public boolean hasNext() { return it1.hasNext() && it2.hasNext(); }

    @Override
    public Pair<T1, T2> next() {
        return new Pair<T1, T2>(it1.next(), it2.next());
    }

    @Override
    public void remove(){
        it1.remove();
        it2.remove();
    }
}

public class IterablePair <T1, T2> implements Iterable<Pair<T1,T2>> {
    private final List<T1> first;
    private final List<T2> second;

    public IterablePair(List<T1> first, List<T2> second) { 
        this.first = first;
        this.second = second;
    }

    @Override
    public Iterator<Pair<T1, T2>> iterator(){
        return new ParallelIterator<T1,T2>( first.iterator(), second.iterator() );
    }
}

void someFunction(){
    IterablePair<X,Y> listPair = new IterablePair<X,Y>( x, y );
    for( Pair<X,Y> pair : listPair ){
        X x = pair.first();
        ...
    }
}

一旦任一列表的元素不足,此操作就会停止,因此您可能需要在创建迭代对之前检查列表的大小是否相等。