Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merge several Collections<A> into a single Collection<A> from a Collection<B> using Guava

What I want to do is very simple using good old loops.

Say I have an object A that contains a List of Bs.

public class A
{
  public List<B> myListOfB;
}

In some other method, I have a List of As. Basically, what I want to do is merge all the elements in the lists of Bs of all my As.

For instance, it's very easy to write something like this using loops :

public List<B> someMethod(List<A> myListOfAs)
{
  List<B> toReturn = new ArrayList<A>();
  for(A myA : myListOfAs)
  {
    toReturn.addAll(myA.myListOfB);
  }
  return toReturn;
}

But I would like to do it in a more fonctionnal way using Guava. This example is very easy, but it could be much more complex with conditions for instance, hence it makes sense to use functional programming.

I'm very new to Guava. I've started using it for filtering and ordering, but I'm pretty sure it might also be possible to use it, but I haven't been able to figure out how. I found this Combine multiple Collections into a single logical Collection? but it doesn't really answer my question.

like image 298
daffycricket Avatar asked Dec 21 '22 22:12

daffycricket


2 Answers

You can use a function to extract the list and concat to flatten the lists. This results in an Iterable.

List<A> input;
Function<A, List<B>> t = new Function<A, List<B>>() {
    @Override public List<B> apply(A input) { 
        return input.myListOfB; 
    }
};
Iterable<B> transform = Iterables.concat(Iterables.transform(input, t));

You can create an List if you need it:

ImmutableList<B> asList = ImmutableList.copyOf(transform);
//or
List<B> newArrayList = Lists.newArrayList(transform);

Note: Normally, public fields of classes are static and immutable or private. Everything else will bring you in trouble.

like image 177
Thomas Jung Avatar answered Dec 23 '22 11:12

Thomas Jung


If you made class A implement Iterable, you could use Iterables.concat().

public class A
    implements Iterable<B>
{
    public List<B> myListOfB;

    // from Iterable
    public Iterator<B> iterator ()
    {
        return myListOfB.iterator();
    }
}

Then:

List<A> listOfAs = ...;
Iterable<B> allBs = Iterables.concat(listOfAs);

To put that in another List:

List<B> listOfAllBs = Lists.newArrayList(allBs);
like image 30
Ray Greenwell Avatar answered Dec 23 '22 11:12

Ray Greenwell