me.at.coding
me.at.coding

Reputation: 17654

Automatically merge several collections to one

I have some Guava Functions like Function<String,Set<String>>. Using those with FluentIterable.transform() leads to a FluentIterable<Set<String>>, however I need a FluentIterable<String>. So my idea now would be to subclass FluentIterable<E> and add a new method transform2() which simply merges everything to one collection before returning it.

The original transform method looks like this:

public final <T> FluentIterable<T> transform(Function<? super E, T> function) {
  return from(Iterables.transform(iterable, function));
}

I thought of something like this for my subclass and transform2() method:

public abstract class FluentIterable2<E> extends FluentIterable<E> 
{       
    public final <T> FluentIterable<T> transform2(Function<? super E, Collection<T>> function) {
        // (PROBLEM 1) Eclipse complains: The field FluentIterable<E>.iterable is not visible  
        Iterable<Collection<T>> iterables = Iterables.transform(iterable, function);

        // (PROBLEM 2) Collection<T> merged = new Collection<T>(); // I need a container / collection - which one?
        for(Collection<T> iterable : iterables)
        {
            // merged.addAll(iterable);
        }

        // return from(merged);
    }
}

Currently I have two problems with my new subclass, marked above with PROBLEM 1 and PROBLEM 2

It would be acceptable if the solution only works with sets, though I'd prefer a solution that works with sets and lists.

Thanks for any hint on this!

Upvotes: 0

Views: 2224

Answers (3)

Tim Peierls
Tim Peierls

Reputation: 390

Use FluentIterable.transformAndConcat(f), where f is a Function mapping an element to some kind of iterable over the element type.

In your case, let's say your Function<String, Set<String>> is called TOKENIZE, and your initial Iterable<String> is called LINES.

Then to get a Set<String> holding all the distinct tokens in LINES, do this:

Iterable<String> LINES = ...;
Function<String, Set<String>> TOKENIZE = ...;
Set<String> TOKENS = FluentIterable.from(LINES)
    .transformAndConcat(TOKENIZE)
    .toSet();

But consider JB Nizet's answer carefully. Try it both ways and see which works better.

Upvotes: 3

ColinD
ColinD

Reputation: 110046

Does FluentIterable.transformAndConcat(stringToSetFunction) not work for your use case?

Upvotes: 6

JB Nizet
JB Nizet

Reputation: 691735

Why subclass FluentIterable just to do this? You just need a simple loop:

Set<String> union = Sets.newHashSet();
for (Set<String> set : fluentIterableOfSets) {
    union.addAll(set);
}

Upvotes: 3

Related Questions