views:

457

answers:

7

Is there a class that represents the concatenation of a collection with another collection? This class should be a Collection in itself, and should delegate all methods to the underlying (inner) collections - no extra memory should be allocated, nor any of the original collections modified.

Example usage:

Collection<String> foo = ...
Collection<String> bar = ...

// this should be O(1) memory and time
Collection<String> combined = concat(foo, bar);

if (combined.contains("Zee"))
  ...

for (String str : combined)
  System.out.println(str);
A: 

I'm not sure what your asking. My interpretation of your question is that your looking for the add method on the Collection. I don't think that's what you're asking though.

Jim Barrows
I'm looking for a collection that encapsulates the concatenation of two collections, _without_ allocating a significant amount of memory or modifying the original collections.
ripper234
+3  A: 

Your question is very vague. Especially "with another item another collection" is quite unclear.

You can at least add the contents of another Collection to the current Collection using Collection#addAll(). Here Collection can be anything of its subinterfaces/implementations, e.g. List or Set.

Example:

List<String> foos = Arrays.asList("foo1", "foo2", "foo3");
List<String> bars = Arrays.asList("bar1", "bar2", "bar3");
foos.addAll(bars); // Now foos contains everything.

Edit: Or do you actually want to create a new Collection based on an existing Collection and then add a new item to it? In this case just construct a new Collection with the existing Collection as constructor argument. E.g.:

List<String> foos = Arrays.asList("foo1", "foo2", "foo3");
List<String> bars = new ArrayList<String>(foos);
bars.add("bar"); // Now bars contains everything.
BalusC
+2  A: 

I think what you're asking for is a Java construct that allows you to put collections together without modifying the original collections. In other words, you have collections A and B, both of size N and M respectively. After the concat call, you still have collections A and B and their sizes are still N and M, however you have collection C as well which points to A and B, making its size N+M.

The answer is no, Java doesn't have anything out of the box that does this... However you could write a quick wrapper that wraps a series of collections and add those collections to it. (All it would do is maintain references to each of the collections) and you could expose get/insert methods as needed.

Malaxeur
That is indeed what I am looking for ... was wondering if there is such a library.
ripper234
+5  A: 

As always for any collections stuff, look at google-collections. If you have Sets, specifically (not just a general collection), you want:

Set<String> combined = Sets.union(foo, bar);

which creates an unmodifiable view of the two sets. That is, changes in 'foo' or 'bar' will be reflected in 'combined' (but combined.add() etc is not supported).

For the more generic case, you have Iterables.concat() but that merely lets you iterate over the joined item, the Iterable interface obviously doesn't include 'contains' so you're a little hosed there.

The other collections utilities classes in google-collections (com.google.common.collect.Lists and com.google.common.collect.Collections2) don't contain any concatenation methods. Don't see why they couldn't, but at the moment they don't.

Cowan
We found that 99% of the time, users really just needed to iterate. Hence Iterables.concat(). Internally we have a Lists.concat() as well but hardlly anyone uses it, and most of those who do could have just used the other one anyway.
Kevin Bourrillion
+1  A: 

There is not, but writing it yourself should be straight forward

package ch.akuhn.util;

import java.util.Iterator;
import java.util.NoSuchElementException;

public class Concat {

    public static <T> Iterable<T> all(final Iterable<T>... iterables) {
        return new Iterable<T>() {
            @Override
            public Iterator<T> iterator() {
                return new Iterator<T>() {
                    Iterator<Iterable<T>> more = Arrays.asList(iterables).iterator();
                    Iterator<T> current = more.hasNext() ? more.next().iterator() : null;
                    @Override
                    public boolean hasNext() {
                        if (current == null) return false;
                        if (current.hasNext()) return true;
                        current = more.hasNext() ? more.next().iterator() : null;
                        return this.hasNext();
                    }

                    @Override
                    public T next() {
                        if (!hasNext()) throw new NoSuchElementException();
                        return current.next();
                    }

                    @Override
                    public void remove() {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
    }

}

And then

for (Object each: Concat.all(collection,whatever,etcetera,...)) {
    // ...
}

Just wrote this code here, compile at your own risk!

PS, if you gonna write unit tests for this class, send 'em to me.

Adrian
A: 

Try InterleavingEnumeration or apache's commons collections' ListUtils (ListUtils.union())

Philippe
+1  A: 

Apache Commons Collections also has a more general CompositeCollection class which can be used as an interface to an arbitrary number of Collections.

bemace