Home > Mobile >  Java stream: Grouping HashMap key values to prevent duplicate keys
Java stream: Grouping HashMap key values to prevent duplicate keys

Time:03-04

I have the following HashMap in my Java app:

final Map<UUID, Boolean> map = demoRepo.demoService.stream()
        .collect(Collectors.toMap(
                ProductDTO::getMenuUuid,
                ProductDTO::getStatus));

However, as the result contains multiple menuUuid value, I need to group them as the key does not contain the same value. So, how should I do this using stream?

Update: I also tried groupingBy as shown below, but I think the usage is not correct:

final Map<UUID, Boolean> map = sdemoRepo.demoService.stream()
                .collect(Collectors.groupingBy(
                        ProductDTO::getMenuUuid, LinkedHashMap::new,
                        Collectors.mapping(ProductDTO::getStatus)));

Suppose that I have the following stream:

MenuUuid   |   Status |
-----------------------
1              true
2              false
1              true
1              true
3              true
2              false

Then I need a map result like; 1:true, 2:false, 3:true

CodePudding user response:

If all the user ids have the same boolean then just do the following:

final Map<UUID, Boolean> map = demoRepo.demoService.stream()
        .collect(Collectors.toMap(
                ProductDTO::getMenuUuid,
                ProductDTO::getStatus,
                (existingValue, newValue)->existingValue));

the last lambda, is a merge function. it is used to make a decision on how to merge duplicate keys. In this case, it just keeps the first that's already there. You could also use the new one since you aren't really altering the boolean and they are all the same value.

If your ProductDTO class uses UUID to determine equality via equals() you could also do the following:

final Map<UUID, Boolean> map = demoRepo.demoService.stream()
        .distinct()
        .collect(Collectors.toMap(
                ProductDTO::getMenuUuid,
                ProductDTO::getStatus));

This works because you won't have any duplicate UUID's

CodePudding user response:

The Collectors.toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) allows the caller to define a BinaryOperator mergeFunction that returns the correct value if the stream provides a key-value pair for a key that already exists.

The following example uses the Boolean.logicalOr method to combine the existing value with the new one. Equal UUID keys are not grouped,since the result is a single key-single value map. But

final Map<UUID, Boolean> map = demoRepo.demoService.stream()
        .collect(Collectors.toMap(
                ProductDTO::getMenuUuid,
                ProductDTO::getStatus,
                 Boolean::logicalOr));

In particular Boolean::logicalOr is a function that is called if the map already contains a value for the key. In this case, the Boolean::logicalOr takes as argument the existing map value and the new value from the Stream` and returns the Logical Or of these two, as the result. This results is then entered in the map.

CodePudding user response:

You will have to merge the values. See if it helps

final Map<UUID, Boolean> map  =
    demoRepo.stream().filter(Objects::nonNull)
        .collect(
            Collectors.toMap(
                ProductDTO::getMenuUuid,
                ProductDTO::getStatus,
                (menuUuid, status) -> {
                  menuUuid.addAll(status);
                  return menuUuid;
                }));
  • Related