1. ホーム
  2. java

[解決済み] 複数のCollectionを1つの論理的なCollectionに統合する?

2022-05-18 05:02:53

質問

あるクラスのメンバーとして一定数のコレクション(例えば3つのArrayList)を持っていると仮定します。今、私はすべての要素を他のクラスに公開したいので、彼らはすべての要素を単純に反復することができます(理想的には、読み取り専用)。 私はguavaコレクションを使用しており、guava iterables/iteratorsを使用して内部コレクションに論理的なビューを生成する方法を疑問に思っています。 を使わずに 一時的なコピーを作成することなく。

どのように解決するのですか?

Guavaでは Iterables.concat(Iterable<T> ...) を使うと、すべての反復記号が1つに連結されたライブビューが作成されます(反復記号を変更すると、連結されたバージョンも変更されます)。次に、連結された反復記号を Iterables.unmodifiableIterable(Iterable<T>) (で囲みます(先ほどは読み取り専用の要件は見ていませんでした)。

から Iterables.concat( .. ) JavaDocsです。

複数の反復記号を一つの 結合する。返されるイテラブルは を走査するイテレータを持つ。 の要素を走査するイテレータを持つ。 入力イテレータは,必要なときまでポーリングされない。 入力イテレータは,必要なときまでポーリングされない。返される のイテレータは remove() をサポートしている場合、対応する入力イテレータ をサポートします。

これはライブビューであることを明示的に述べていませんが、最後の文はライブビューであることを暗示しています(対応する入力イテレータが Iterator.remove() メソッドをサポートすることは、ライブビューを使用しない限り不可能です)。

サンプルコードです。

final List<Integer> first  = Lists.newArrayList(1, 2, 3);
final List<Integer> second = Lists.newArrayList(4, 5, 6);
final List<Integer> third  = Lists.newArrayList(7, 8, 9);
final Iterable<Integer> all =
    Iterables.unmodifiableIterable(
        Iterables.concat(first, second, third));
System.out.println(all);
third.add(9999999);
System.out.println(all);

出力します。

[1, 2, 3, 4, 5, 6, 7, 8, 9]

[1, 2, 3, 4, 5, 6, 7, 8, 9, 9999999]


編集します。

Damianからのリクエストで、ライブのコレクションビューを返す同様のメソッドを紹介します。

public final class CollectionsX {

    static class JoinedCollectionView<E> implements Collection<E> {

        private final Collection<? extends E>[] items;

        public JoinedCollectionView(final Collection<? extends E>[] items) {
            this.items = items;
        }

        @Override
        public boolean addAll(final Collection<? extends E> c) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void clear() {
            for (final Collection<? extends E> coll : items) {
                coll.clear();
            }
        }

        @Override
        public boolean contains(final Object o) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean containsAll(final Collection<?> c) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean isEmpty() {
            return !iterator().hasNext();
        }

        @Override
        public Iterator<E> iterator() {
            return Iterables.concat(items).iterator();
        }

        @Override
        public boolean remove(final Object o) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean removeAll(final Collection<?> c) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean retainAll(final Collection<?> c) {
            throw new UnsupportedOperationException();
        }

        @Override
        public int size() {
            int ct = 0;
            for (final Collection<? extends E> coll : items) {
                ct += coll.size();
            }
            return ct;
        }

        @Override
        public Object[] toArray() {
            throw new UnsupportedOperationException();
        }

        @Override
        public <T> T[] toArray(T[] a) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean add(E e) {
            throw new UnsupportedOperationException();
        }

    }

    /**
     * Returns a live aggregated collection view of the collections passed in.
     * <p>
     * All methods except {@link Collection#size()}, {@link Collection#clear()},
     * {@link Collection#isEmpty()} and {@link Iterable#iterator()}
     *  throw {@link UnsupportedOperationException} in the returned Collection.
     * <p>
     * None of the above methods is thread safe (nor would there be an easy way
     * of making them).
     */
    public static <T> Collection<T> combine(
        final Collection<? extends T>... items) {
        return new JoinedCollectionView<T>(items);
    }

    private CollectionsX() {
    }

}