6

I would like to build a Map using the Stream & Lambda couple.

I've tried many ways but I'm stucked. Here's the classic Java code to do it using both Stream/Lambda and classic loops.

Map<Entity, List<Funder>> initMap = new HashMap<>();
List<Entity> entities = pprsToBeApproved.stream()
    .map(fr -> fr.getBuyerIdentification().getBuyer().getEntity())
    .distinct()
    .collect(Collectors.toList());

for(Entity entity : entities) {
    List<Funder> funders = pprsToBeApproved.stream()
        .filter(fr -> fr.getBuyerIdentification().getBuyer().getEntity().equals(entity))
        .map(fr -> fr.getDocuments().get(0).getFunder())
        .distinct()
        .collect(Collectors.toList());
    initMap.put(entity, funders);
        }

As you can see, I only know how to collect in a list, but I just can't do the same with a map. That's why I have to stream my list again to build a second list to, finally, put all together in a map. I've also tried the 'collect.groupingBy' statement as it should too produce a map, but I failed.

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Lovegiver
  • 413
  • 6
  • 22

1 Answers1

7

It seems you want to map whatever is on the pprsToBeApproved list to your Funder instances, grouping them by buyer Entity.

You can do it as follows:

Map<Entity, List<Funder>> initMap = pprsToBeApproved.stream()
    .collect(Collectors.groupingBy(
        fr -> fr.getBuyerIdentification().getBuyer().getEntity(), // group by this
        Collectors.mapping(
            fr -> fr.getDocuments().get(0).getFunder(), // mapping each element to this
            Collectors.toList())));                     // and putting them in a list

If you don't want duplicate funders for a particular entity, you can collect to a map of sets instead:

Map<Entity, Set<Funder>> initMap = pprsToBeApproved.stream()
    .collect(Collectors.groupingBy(
        fr -> fr.getBuyerIdentification().getBuyer().getEntity(),
        Collectors.mapping(
            fr -> fr.getDocuments().get(0).getFunder(),
            Collectors.toSet())));

This uses Collectors.groupingBy along with Collectors.mapping.

fps
  • 33,623
  • 8
  • 55
  • 110
  • 1
    Just to my response to be complete : - first snippet works but duplicates datas, what is not good for me as I wanted to group entries - second snippet is just fine and gives me the same result I reached with my poor code. One more thing : in the 2 cases, I have to replace the real objects I use (Entity and Funder) by Object : Map> initMap =... I don't understand why. Casting my own classes don't work. I also discover that I'm not ease with the Set object. I really never use it, maybe because I don't know what it really usefull for. – Lovegiver Oct 10 '18 at 14:17
  • 1
    I know @Eugene, I was just writing my answer. No stress ^^ – Lovegiver Oct 10 '18 at 14:18
  • 2
    @Lovegiver `Set` is a collection that doesn't allow duplicates. As to `Map> initMap = ...`, I don't understand why the compiler is not infering the correct types. Does `fr.getBuyerIdentification().getBuyer().getEntity()` return an object of type `Entity`? And does `fr.getDocuments().get(0).getFunder()` return an object of type `Funder`? If yes to both, then you shouldn't have any problem. – fps Oct 10 '18 at 14:24
  • Damn you're right @Federico !! fr.getDocuments().get(0).getFunder() returns a Funder but fr.getBuyerIdentification().getBuyer().getEntity() returns just a String with the name of the Entity. I don't know why the binding between this 2 objects has been made this way (a String, not the class itself). – Lovegiver Oct 10 '18 at 14:37