web-dev-qa-db-ja.com

Javaでイテレータをマージすることは可能ですか?

Javaでイテレータをマージすることは可能ですか? 2つのイテレータがあり、それらを結合/マージして、2つのステップではなく1つの要素(同じループ内)でそれらの要素を反復処理できるようにします。それは可能ですか?

2つのリスト内の要素の数は異なる場合があるため、両方のリストを1回ループするだけでは解決できないことに注意してください。

Iterator<User> pUsers = userService.getPrimaryUsersInGroup(group.getId());
Iterator<User> sUsers = userService.getSecondaryUsersInGroup(group.getId());

while(pUsers.hasNext()) {
  User user = pUsers.next();
  .....
}

while(sUsers.hasNext()) {
  User user = sUsers.next();
  .....
}
45
Jahanzeb Farooq

Guava (以前のGoogleコレクション)には Iterators.concat があります。

50
Andrew Duffy

また、 Apache Commons Collection には、 IteratorChain のように、イテレータを操作するためのいくつかのクラスがあり、いくつかのイテレータをラップしています。

20
Ither

イテレータを反復するIteratorインターフェースの独自の実装を作成できます。

_public class IteratorOfIterators implements Iterator {
    private final List<Iterator> iterators;

    public IteratorOfIterators(List<Iterator> iterators) {
        this.iterators = iterators;
    }

    public IteratorOfIterators(Iterator... iterators) {
        this.iterators = Arrays.asList(iterators);
    }


    public boolean hasNext() { /* implementation */ }

    public Object next() { /* implementation */ }

    public void remove() { /* implementation */ }
}
_

(簡潔にするため、イテレータにジェネリックを追加していません。)実装はそれほど難しくはありませんが、それほど簡単ではありません。現在反復しているIteratorを追跡し、next()を呼び出すと、hasNext()が見つかるまで、イテレータを可能な限り反復する必要があります。これはtrueを返します。または、最後のイテレータの終わりに到達する場合があります。

このための既存の実装については知りません。

更新:
私は賛成投票しました Andrew Duffy's 答え-車輪を再発明する必要はありません。私は本当にグアバをより深く調査する必要があります。

可変数の引数用に別のコンストラクターを追加しました-ここでクラスがどのように構築されるかはあまり重要ではなく、それがどのように機能するかの概念だけなので、ほとんど話題から外れています。

16
Noel M

私はJavaコードをしばらく書いていないので、これがまだ「理解した」かどうかに興味を持った。

初挑戦:

import Java.util.Iterator;
import Java.util.Arrays; /* For sample code */

public class IteratorIterator<T> implements Iterator<T> {
    private final Iterator<T> is[];
    private int current;

    public IteratorIterator(Iterator<T>... iterators)
    {
            is = iterators;
            current = 0;
    }

    public boolean hasNext() {
            while ( current < is.length && !is[current].hasNext() )
                    current++;

            return current < is.length;
    }

    public T next() {
            while ( current < is.length && !is[current].hasNext() )
                    current++;

            return is[current].next();
    }

    public void remove() { /* not implemented */ }

    /* Sample use */
    public static void main(String... args)
    {
            Iterator<Integer> a = Arrays.asList(1,2,3,4).iterator();
            Iterator<Integer> b = Arrays.asList(10,11,12).iterator();
            Iterator<Integer> c = Arrays.asList(99, 98, 97).iterator();

            Iterator<Integer> ii = new IteratorIterator<Integer>(a,b,c);

            while ( ii.hasNext() )
                    System.out.println(ii.next());
    }
}

あなたcouldもちろん、純粋な配列+インデックスカウンターではなく、より多くのコレクションクラスを使用しますが、これは実際には、代替よりも少しクリーンに感じられます。または私は最近、ほとんどCを書くことから偏っていますか?

とにかく、あなたは行き​​ます。あなたの質問への答えは「はい、おそらく」です。

13
Christoffer
public class IteratorJoin<T> implements Iterator<T> {
    private final Iterator<T> first, next;

    public IteratorJoin(Iterator<T> first, Iterator<T> next) {
        this.first = first;
        this.next = next;
    }

    @Override
    public boolean hasNext() {
        return first.hasNext() || next.hasNext();
    }

    @Override
    public T next() {
        if (first.hasNext())
            return first.next();
        return next.next();
    }
}
4
clelson

ループをメソッドに移動し、イテレーターをメソッドに渡します。

void methodX(Iterator x) {
    while (x.hasNext()) {
        ....
    }
}
3
mhshams

イテレータはコレクションまたはセットから取得されます。
すでに利用可能な方法を使用しない理由
Collection.addAll(Collection c);
そして最後のオブジェクトからイテレータを作成します。
この方法で、イテレータは両方のコレクションのすべてのコンテンツを反復します。

3
p01ntbl4nk

拡張可能なイテレータの my version を使用できます。それは私には理にかなっているイテレータの両端キューを使用します:

import Java.util.Deque;
import Java.util.Iterator;
import Java.util.concurrent.ConcurrentLinkedDeque;

public class ExtendableIterator<T> implements Iterator<T> {

    public Deque<Iterator<T>> its = new ConcurrentLinkedDeque<Iterator<T>>();

    public ExtendableIterator() {

    }

    public ExtendableIterator(Iterator<T> it) {
        this();
        this.extend(it);
    }

    @Override
    public boolean hasNext() {
        // this is true since we never hold empty iterators
        return !its.isEmpty() && its.peekLast().hasNext();
    }

    @Override
    public T next() {
        T next = its.peekFirst().next();
        if (!its.peekFirst().hasNext()) {
            its.removeFirst();
        }
        return next;
    }

    public void extend(Iterator<T> it) {
        if (it.hasNext()) {
            its.addLast(it);
        }
    }
}
2
Reut Sharabani

Java 8以降では、これは Stream API を使用して外部の依存関係なしで実行できます。これにより、イテレータを他のタイプのストリームと連結することもできます。

Streams.concat(StreamSupport.stream(<iter1>, false), StreamSupport.stream(<iter2>, false));
2
Taras Alenin

私は元のデザインを以下からリファクタリングします:

Iterator<User> pUsers = userService.getPrimaryUsersInGroup(group.getId());
Iterator<User> sUsers = userService.getSecondaryUsersInGroup(group.getId());

次のようなものに:

Iterator<User> users = userService.getUsersInGroup(group.getId(), User.PRIMARY, User.SECONDARY, ...);
1

Apache Commons Collections には public static <E> Iterator<E> org.Apache.commons.collections4.IteratorUtils.chainedIterator(Collection<Iterator<? extends E>> iterators) とあります

イテレータのコレクションを次々と反復するイテレータを取得します。

あなたが望むものでなければなりません。

import Java.util.Arrays;
import Java.util.Iterator;

import org.Apache.commons.collections4.IteratorUtils;
//also works: import org.Apache.commons.collections.IteratorUtils;

class Scratch {
    public static void main( String[] args ) {
        final Iterator<String> combinedIterator = IteratorUtils.chainedIterator(
                Arrays.asList( "a", "b", "c" ).iterator(),
                Arrays.asList( "1", "2", "3" ).iterator()
            );
        while( combinedIterator.hasNext() ){
            System.out.println( combinedIterator.next() );
        }
        // "abc123" will have been printed out
    }
}
1
Sled

あなたは試すことができます ConcatIterator from Cactoos

Iterator<String> names = new ConcatIterator<>(
  Arrays.asList("Sarah", "Mary").iterator(),
  Arrays.asList("Jeff", "Johnny").iterator(),
);

また、ConcatIterablesを連結する Iterable も確認してください。

1
yegor256

マージされたイテレータ:

import static Java.util.Arrays.asList;

import Java.util.Iterator;
import Java.util.LinkedList;
import Java.util.List;
import Java.util.NoSuchElementException;


public class ConcatIterator<T> implements Iterator<T> {

    private final List<Iterable<T>> iterables;
    private Iterator<T> current;

    @SafeVarargs
    public ConcatIterator(final Iterable<T>... iterables) {
        this.iterables = new LinkedList<>(asList(iterables));
    }

    @Override
    public boolean hasNext() {
        checkNext();
        return current != null && current.hasNext();
    }

    @Override
    public T next() {
        checkNext();
        if (current == null || !current.hasNext()) throw new NoSuchElementException();
        return current.next();
    }

    @Override
    public void remove() {
        if (current == null) throw new IllegalStateException();
        current.remove();
    }

    private void checkNext() {
        while ((current == null || !current.hasNext()) && !iterables.isEmpty()) {
            current = iterables.remove(0).iterator();
        }
    }

}

concatを作成するIterableメソッド:

@SafeVarargs
public static <T> Iterable<T> concat(final Iterable<T>... iterables) {
    return () -> new ConcatIterator<>(iterables);
}

簡単なJUnitテスト:

@Test
public void testConcat() throws Exception {
    final Iterable<Integer> it1 = asList(1, 2, 3);
    final Iterable<Integer> it2 = asList(4, 5);
    int j = 1;
    for (final int i : concat(it1, it2)) {
        assertEquals(j, i);
        j++;
    }
}
1
benez

すべてのIteratorオブジェクトは独自のメモリ位置(adress)を保持するため、単純に「マージ」することはできません。 iteratorクラスを拡張して、独自の実装をそこに作成する場合を除きます。

両方のイテレータで同じ数のオブジェクトを処理している場合、別の解決策は、次のように1つのループで2つのイテレータを処理することです。

   while (iterator1.hasNext() && iterator2.hasNext()) {
      // code
    }
0
Youssef