Skip to content
Advertisement

How do i group by the contents of a string list using collect() of a Stream?

I have a database object that has a field that contains a list of strings. I retrieve all these objects and then use the flatMap and distinct stream methods on the resulting list to get a new list that holds all possible unique values that a database object string list can contain.

Next i want to make a map where the keys are the unique values list of the stringlist that i made earlier, and the values of the map are a list of database objects whose stringlist contains the value of the respective string mapkey.

So what I want is groupingBy the following:

if(object.stringList().contains(respectiveMapKeyFromUniqeStringCollection) put object in object values list of that respective keymap.

Is something like this possible using the groupingBy method?

Edit: I will explain further

class VegetableMaker{
@ElementCollection  
private List<String> vegetableList;

}

Lets assume the possible values that a vegetableList can contain are: “Lettuce, Tomato, spinache, rubarbe, onion”

Set<String> produceNames = vegetableMakers.stream().flatMap(vegetableMaker -> vegetableMaker.getVegetableList().stream())
    .distinct().collect(Collectors.toSet());

Now we have the list that contains all the possible values mentioned before.

We want to use the values in this list as the keys in the map.

So the Map will look like:

Map<uniqueStringsAsKeys, List<VegetableMaker>> map

The list value contains all the VegetableMaker instances of which the vegetableList contains the key of the map. So the list of key Onion will contain all the VegetableMaker instances whose list includes “Onion”.

Is it possible to achieve such a map using the groupingBy method of a java stream?

EDIT 2:

This is the solution i have now, that doesn’t use groupingBy but clarifies even more what I want.

EDIT: changed variable in code to match variables used in previous examples.

Set<VegetableMaker> vegetableMakers = vegetableMakerDao.findAll();
Set<String> uniqueVegetableList = vegetableMakers.stream().flatMap(vegetableMaker -> affiliateLink.getKeywords().stream()).distinct().collect(Collectors.toSet());
Map<String,Set<VegetableMaker>> vegetableMakersContainingKeywordInTheirList = new HashMap<>();

uniqueVegetableList.forEach(produceName ->{
    Set<VegetableMaker> vegetableMakerSet = new HashSet<>();
    vegetableMakers.forEach( vegetableMaker -> {
        if(vegetableMaker.getVegetableList().contains(produceName))
            vegetableMakerSet.add(vegetableMaker);
    });
    vegetableMakersContainingKeywordInTheirList.put(produceName, vegetableMakerSet);
});

Advertisement

Answer

If I understood you correctly:

List<VegetableMaker> dbObjects = List.of(
            new VegetableMaker("Salad", List.of("Onion", "Cucumber")),
            new VegetableMaker("Italian Salad", List.of("Cheese")),
            new VegetableMaker("Greek Salad", List.of("Onion")));

    Map<String, List<VegetableMaker>> map = dbObjects.stream()
            .flatMap(x -> x.getVegetableList().stream().map(y -> new SimpleEntry<>(x, y)))
            .collect(Collectors.groupingBy(
                    Entry::getValue,
                    Collectors.mapping(Entry::getKey, Collectors.toList())));

    System.out.println(map); 

Resulting being something like:

{Onion=[Salad, Greek Salad], Cheese=[Italian Salad], Cucumber=[Salad]}

EDIT

This is not much different than what I posted above:

Map<String, Set<VegetableMaker>> result = vegetableMakerList.stream()
            .flatMap(x -> x.getKeywords().stream().distinct().map(y -> new SimpleEntry<>(x, y)))
            .collect(Collectors.groupingBy(
                    Entry::getValue,
                    Collectors.mapping(Entry::getKey, Collectors.toSet())));
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement