Search code examples
javacollectionsguavamultiset

Merge several Guava multisets into one


I would like to create an immutable view on the sum of a number (>2) of immutable Guava multisets. The multisets are in a list. I don't want to copy the contents into a new multiset. I could probably use Multisets.sum(Multiset, Multiset) and reduce my stream of Multisets with it, but it seems a bit wasteful to create a summed multiset for every intermediate step. Is there a better way?

In other words: I want a method similar to Multisets.sum(Multiset, Multiset), but then for a list of multisets instead of just two. The signature could be: <T> Multiset<T> sum(List<Multiset<T>>).


Solution

  • Actually Multisets.sum(Multiset, Multiset) is implemented in the way it doesn't copy contents but rather creates a view over two multisets, so in your case looping over list of multisets and copying only final result to a new immutable multiset is fine (overhead from views should not matter for small number of multisets). Using Java 8 you can combine Multiset's sum with Stream#reduce:

    public <T> Multiset<T> sum(final List<Multiset<T>> multisets)
    {
        return multisets.stream().reduce(ImmutableMultiset.of(), Multisets::sum);
    }
    

    EDIT

    However although there'll be no copying involved in approach above, as @LouisWasserman noted most optimal solution (YMMV) could be just accumulate results in new multiset:

    public <T> ImmutableMultiset<T> sum(final List<Multiset<T>> multisets)
    {
        final ImmutableMultiset.Builder<T> builder = ImmutableMultiset.builder();
        multisets.forEach(builder::addAll);
        return builder.build();
    }
    

    Having dedicated view class (see @OliverGregoire's answer) is also an option if needed.