将多个集合合并为一个逻辑集合?

假设,我有一个固定数量的集合(例如3个ArrayLists)作为一个类的成员。 现在,我想将所有元素公开给其他类,以便它们可以遍历所有元素(理想情况下,只读)。 我正在使用番石榴集合,我想知道如何使用番石榴iterables /迭代器生成内部集合的逻辑视图, 而不做临时副本。

使用番石榴,你可以使用Iterables.concat(Iterable<T> ...) ,它创build一个所有迭代的实时视图,连接成一个(如果你改变迭代,连接的版本也会改变)。 然后用Iterables.unmodifiableIterable(Iterable<T>)包装连接的迭代(我以前没有见过只读要求)。

Iterables.concat( .. ) JavaDocs:

将多个迭代器组合成一个迭代器。 返回的迭代器有一个遍历input中每个迭代元素的迭代器。 input迭代器直到必要时才被轮询。 返回的迭代器的迭代器在相应的input迭代器支持时支持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() { } } 

使用Stream简单Java 8解决scheme。

常数

假设private Collection<T> c, c2, c3

一个解决scheme

 public Stream<T> stream() { return Stream.concat(Stream.concat(c.stream(), c2.stream()), c3.stream()); } 

另一个scheme

 public Stream<T> stream() { return Stream.of(c, c2, c3).flatMap(Collection::stream); } 

可变数字

假设private Collection<Collection<T>> cs

 public Stream<T> stream() { return cs.stream().flatMap(Collection::stream); } 

如果您至less使用Java 8,请参阅我的其他答案 。

如果您已经在使用Google Guava,请参阅Sean Patrick Floyd的回答 。

如果你被困在Java 7中,并且不想包含Google Guava,那么你可以使用不超过IterableIterator来编写自己的(只读) Iterables.concat()

常数

 public static <E> Iterable<E> concat(final Iterable<? extends E> iterable1, final Iterable<? extends E> iterable2) { return new Iterable<E>() { @Override public Iterator<E> iterator() { return new Iterator<E>() { final Iterator<? extends E> iterator1 = iterable1.iterator(); final Iterator<? extends E> iterator2 = iterable2.iterator(); @Override public boolean hasNext() { return iterator1.hasNext() || iterator2.hasNext(); } @Override public E next() { return iterator1.hasNext() ? iterator1.next() : iterator2.next(); } }; } }; } 

可变数字

 @SafeVarargs public static <E> Iterable<E> concat(final Iterable<? extends E>... iterables) { return concat(Arrays.asList(iterables)); } public static <E> Iterable<E> concat(final Iterable<Iterable<? extends E>> iterables) { return new Iterable<E>() { final Iterator<Iterable<? extends E>> iterablesIterator = iterables.iterator(); @Override public Iterator<E> iterator() { return !iterablesIterator.hasNext() ? Collections.emptyIterator() : new Iterator<E>() { Iterator<? extends E> iterableIterator = nextIterator(); @Override public boolean hasNext() { return iterableIterator.hasNext(); } @Override public E next() { final E next = iterableIterator.next(); findNext(); return next; } Iterator<? extends E> nextIterator() { return iterablesIterator.next().iterator(); } Iterator<E> findNext() { while (!iterableIterator.hasNext()) { if (!iterablesIterator.hasNext()) { break; } iterableIterator = nextIterator(); } return this; } }.findNext(); } }; } 

你可以创build一个新的List并将其他ListaddAll()到它。 然后用Collections.unmodifiableList()返回一个不可修改的列表。

这是我的解决scheme:

编辑 – 改变了一点点的代码

 public static <E> Iterable<E> concat(final Iterable<? extends E> list1, Iterable<? extends E> list2) { return new Iterable<E>() { public Iterator<E> iterator() { return new Iterator<E>() { protected Iterator<? extends E> listIterator = list1.iterator(); protected Boolean checkedHasNext; protected E nextValue; private boolean startTheSecond; public void theNext() { if (listIterator.hasNext()) { checkedHasNext = true; nextValue = listIterator.next(); } else if (startTheSecond) checkedHasNext = false; else { startTheSecond = true; listIterator = list2.iterator(); theNext(); } } public boolean hasNext() { if (checkedHasNext == null) theNext(); return checkedHasNext; } public E next() { if (!hasNext()) throw new NoSuchElementException(); checkedHasNext = null; return nextValue; } public void remove() { listIterator.remove(); } }; } }; }