Объединить несколько коллекций в одну логическую коллекцию?
Предположим, у меня есть постоянное количество коллекций (например, 3 ArrayLists) в качестве членов класса. Теперь я хочу предоставить все элементы другим классам, чтобы они могли просто перебирать все элементы (в идеале, только для чтения). Я использую коллекции guava и мне интересно, как я мог бы использовать Guava iterables/iterators для создания логического представления на внутренних коллекциях без создание временных копий.
5 ответов:
С гуавой, вы можете использовать
Iterables.concat(Iterable<T> ...)
, он создает живое представление всех iterables, объединенных в один (если вы измените iterables, объединенная версия также изменится). Затем оберните объединенную итерацию сIterables.unmodifiableIterable(Iterable<T>)
(Я не видел требование только для чтения ранее).С
Iterables.concat( .. )
JavaDocs:объединяет несколько итераций в a один итерируемый. Возвращаемый итератор есть итератор, который проходит элементы каждой итерации во входных данных. Входные итераторы не опрашиваются пока это необходимо. Возвращенный итератор итератор поддерживает
remove()
когда соответствующий входной итератор поддерживать ее.хотя это явно не говорит о том, что это живой вид, последнее предложение подразумевает, что он (поддерживает
Iterator.remove()
метод только в том случае, если поддержка итератора поддержки невозможна, если не используется живой view)Пример Кода:
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]
Edit:
по запросу от Дамиана, вот аналогичный метод, который возвращает live Collection View
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() { } }
простые решения Java 8 с использованием
Stream
.постоянная
предполагая, что
private Collection<T> c, c2, c3
.решение:
public Stream<T> stream() { return Stream.concat(Stream.concat(c.stream(), c2.stream()), c3.stream()); }
другое решение:
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); }
если вы используете хотя бы Java 8, см. мой другой ответ.
если вы уже используете Google Guava, см. ответ Шона Патрика Флойда.
если вы застряли на Java 7 и не хотите включать Google Guava, вы можете написать свой собственный (только для чтения)
Iterables.concat()
используя не болееIterable
иIterator
:постоянная
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(); } }; }
вы можете создать новый
List
иaddAll()
другиеList
s к нему. Затем верните неизменяемый список с помощьюCollections.unmodifiableList()
.
вот мое решение для этого:
редактировать-немного изменил код
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(); } }; } }; }