Połączyć wiele kolekcji w jedną kolekcję logiczną?
Załóżmy, że mam stałą liczbę zbiorów (np. 3 ArrayLists) jako członków klasy. Teraz chcę udostępnić wszystkie elementy innym klasom, aby mogły po prostu iterować wszystkie elementy (najlepiej tylko do odczytu). Używam kolekcji guava i zastanawiam się, jak mógłbym użyć iterables/iteratorów guava, aby wygenerować logiczny widok na wewnętrzne Kolekcje Bez tworzenia tymczasowych kopii.
5 answers
Z guawa, można użyć Iterables.concat(Iterable<T> ...)
, tworzy aktywny widok wszystkich iterabli, skonkatenowanych w jeden (jeśli zmienisz iterabli, skonkatenowana Wersja również się zmieni). Następnie zawinąć konkatenowany iterowalny z Iterables.unmodifiableIterable(Iterable<T>)
(nie widziałem wcześniej wymogu tylko do odczytu).
Z Iterables.concat( .. )
JavaDocs:
Łączy wiele iterabli w pojedyncze iterowalne. The returned iterable posiada iterator, który przemierza elementy każdego iterable input. Iteratory wejściowe nie są ankietowane dopóki nie będzie to konieczne. The returned iterable obsługuje iterator
remove()
gdy odpowiedni iterator wejściowy wspiera.
Chociaż to nie mówi wprost, że jest to Widok na żywo, ostatnie zdanie sugeruje, że jest (wspieranie Iterator.remove()
metoda tylko wtedy, gdy iterator wspierający ją obsługuje, nie jest możliwa, chyba że używa live view)
Próbka Kod:
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);
Wyjście:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 9999999]
Edit:
Na prośbę Damiana, oto podobna metoda, która zwraca widok live Collection
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() {
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-29 10:19:24
Plain Java 8 solutions using a Stream
.
Stała liczba
Zakładając private Collection<T> c, c2, c3
.
Jedno rozwiązanie:
public Stream<T> stream() {
return Stream.concat(Stream.concat(c.stream(), c2.stream()), c3.stream());
}
Inne rozwiązanie:
public Stream<T> stream() {
return Stream.of(c, c2, c3).flatMap(Collection::stream);
}
Liczba zmienna
Zakładając private Collection<Collection<T>> cs
:
public Stream<T> stream() {
return cs.stream().flatMap(Collection::stream);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-18 19:51:52
Jeśli używasz co najmniej Java 8, Zobacz moja inna odpowiedź .
Jeśli już korzystasz z Google Guava, Zobacz odpowiedź Seana Patricka Floyda .
Jeśli utknąłeś w Javie 7 i nie chcesz dołączać Google Guava, możesz napisać swój własny (tylko do odczytu) Iterables.concat()
używając nie więcej niż Iterable
i Iterator
:
Stała liczba
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();
}
};
}
};
}
Liczba zmienna
@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();
}
};
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-07 03:51:33
Możesz utworzyć nowe List
i addAll()
swoich innych List
do niego. Następnie zwróć niezmodyfikowaną listę za pomocą Collections.unmodifiableList()
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-08 11:38:50
Oto moje rozwiązanie na to:
Edycja-zmieniono trochę kod
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();
}
};
}
};
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-07 16:30:34