Combine multiple Collections into a single logical Collection?

Assume, I have a constant number of collections (e.g. 3 ArrayLists) as members of a class. Now, I want to expose all the elements to other classes so they can simply iterate over all elements (ideally, read only). I'm using guava collections and I wonder how I could use guava iterables/iterators to generate a logical view on the internal collections without making temporary copies.

118825 次浏览

您可以为它创建一个新的 List和其他 ListaddAll()。然后使用 Collections.unmodifiableList()返回一个不可修改的列表。

使用 Guava 时,您可以使用 Iterables.concat(Iterable<T> ...),它创建所有迭代器的实时视图,并将其连接为一个(如果您更改了迭代器,连接的版本也会更改)。然后用 Iterables.unmodifiableIterable(Iterable<T>)包装连接的迭代文件(我之前没有看到只读需求)。

来自 Iterables.concat( .. ) JavaDocs:

将多个迭代组合成 返回的迭代 有一个遍历 输入中每个可迭代的元素。 不轮询输入迭代器 直到必要的时候,归来者 Iterable 的迭代器支持 remove() 当相应的输入迭代器 支持它。

虽然这并没有明确说明这是一个实时视图,但是最后一句话暗示它是(只有在支持迭代器支持的情况下才支持 Iterator.remove()方法,除非使用实时视图)

Sample Code:

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);

Output:

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


编辑:

通过 Damian 的 Request,这里有一个类似的方法,它返回一个实时的 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() {
}


}

使用 Stream的普通 Java8解决方案。

Constant number

假设 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);
}

Here is my solution for that:

稍微修改一下代码

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();
}
};
}
};
}

If you're using at least Java 8, see my other answer.

如果您已经在使用谷歌番石榴,请参阅 Sean Patrick Floyd 的回答

如果你停留在 Java 7,不想包括 Google Guava,你可以写自己的(只读) Iterables.concat()使用不超过 IterableIterator:

常数

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();
}
};
}