Java 8 Collectors.groupingBy with mapped value to set collecting result to the same set

java stream groupingby map value
java 8 group by multiple fields
java 8 multi level grouping
java 8 group by and reduce
java 8 stream group by sum multiple fields
java stream group by sum bigdecimal
java stream group by max
java 7 collection group by

Objects are used in example are from package org.jsoup.nodes

import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

I need group attributes by key with resulting value Set.

Optional<Element> buttonOpt = ...;
Map<String, Set<String>> stringStringMap =
    buttonOpt.map(button -> button.attributes().asList().stream()
            .collect(groupingBy(Attribute::getKey, 
                  mapping(attribute -> attribute.getValue(), toSet()))))
            .orElse(new HashMap<>());

It seems collected correctly, but value all the time is single string (because of library implementation) that contains different values split by space. Trying to improve solution:

Map<String, Set<HashSet<String>>> stringSetMap = buttonOpt.map(
        button -> button.attributes()
            .asList()
            .stream()
            .collect(groupingBy(Attribute::getKey, 
                        mapping(attribute -> 
                          new HashSet<String>(Arrays.asList(attribute.getValue()
                                                                .split(" "))),
                   toSet()))))
  .orElse(new HashMap<>());

In result i've got different structure Map<String, Set<HashSet<String>>> but i need Map<String, Set<String>>

I've checked some collectors but have not managed my issue.

Question is:

How to merge all sets that related to the same attribute key?

You can split your attributes with flatMap and create new entries to group:

Optional<Element> buttonOpt = ...
Map<String, Set<String>> stringStringMap =
        buttonOpt.map(button -> 
            button.attributes()
                  .asList()
                  .stream()
                  .flatMap(at -> Arrays.stream(at.getValue().split(" "))
                                       .map(v -> new SimpleEntry<>(at.getKey(),v)))
                  .collect(groupingBy(Map.Entry::getKey, 
                                      mapping(Map.Entry::getValue, toSet()))))
                .orElse(new HashMap<>());

Guide to Java 8 groupingBy Collector, A guide to Java 8 groupingBy Collector with usage examples. They are used for grouping objects by some property and storing results in a Map instance. The value that is returned by the function is used as a key to the map Let's use the toSet() collector as the downstream collector and get a Set of  A guide to Java 8 groupingBy Collector with usage examples. The Java 8 Stream API lets us process collections of data in a declarative way.. The static factory methods Collectors.groupingBy() and Collectors.groupingByConcurrent() provide us with functionality similar to the ‘GROUP BY' clause in the SQL language.

Here's a Java9 way of doing it,

Map<String, Set<String>> stringSetMap = buttonOpt
    .map(button -> button.attributes().asList().stream()
        .collect(Collectors.groupingBy(Attribute::getKey, Collectors.flatMapping(
            attribute -> Arrays.stream(attribute.getValue().split(" ")), Collectors.toSet()))))
    .orElse(Collections.emptyMap());

Java 8 – Stream Collectors groupingBy examples, In this article, we will show you how to use Java 8 Stream Collectors to group Map<BigDecimal, Set<String>> result = items.stream().collect(  It appears the result in the example in section 3.12, “Collectors.groupingBy()” is wrong. The result map should only contain entries for 1, 2, and 3. Either that, or I’m missing something… 🙂

This becomes less complicated if you use a more suitable data structure for it, namely a multimap.

Multimaps are present e.g. in Guava, where you can do this as follows:

SetMultimap<String, String> stringMultimap = buttonOpt
        .map(button -> button.attributes().asList().stream()
                .collect(ImmutableSetMultimap.flatteningToImmutableSetMultimap(
                        Attribute::getKey,
                        attribute -> Arrays.stream(attribute.getValue().split(" "))
                ))
        ).orElse(ImmutableSetMultimap.of());

I made it immutable (ImmutableSetMultimap), but a mutable version can also be obtained using Multimaps.flatteningToMultimap.

java.util.stream.Collectors.groupingBy java code examples, Collectors.groupingBy (Showing top 20 results out of 6,390). Refine search. Stream.collect · List.stream · Stream.map · Map.entrySet · Set.stream · Stream.​filter. Java 8 Collectors.groupingBy with mapped value to set collecting result to the same set. (Collectors.groupingBy(Attribute::getKey, Collectors.flatMapping

Java 8 Grouping with Collectors, Tutorial on Java 8 groupingBy Collector with examples explains 3 stored by the grouping collector in a Map<R, Collection<T>> , i.e. each 'key,value' entry The output with employees grouped in Sets looks the same as 1st  Introduction: GroupingBy Collectors introduced in Java 8 provides us a functionality much similar to using GROUP BY clause in a SQL statement. It helps us group objects based on certain property, returning a Map as an outcome. In this article, we’ll look at various example usages of the groupingBy collector in Java 8. To follow …

Collectors groupingBy with Examples, Basic groupingBy; Using a Custom collector; Custom map supplier The groupingBy we are discussing here has the same result as the The value is the list of stream elements that were mapped to the same K by the Map<String, Set​<Long>> departmentToStudentIds Tags: collectors, java8-streams  In this article, we will show you how to use Java 8 Stream Collectors to group by, count, sum and sort a List.. 1. Group By, Count and Sort. 1.1 Group by a List and display the total count of it.

Collectors (Java Platform SE 8 ), groupingBy(Employee::getDepartment)); // Compute sum of salaries by them into a Map<Boolean, D> whose values are the result of the downstream reduction. Returns a Collector that accumulates the input elements into a new Set . values associated with the same key, as supplied to Map.merge(Object, Object,  If a partition has no elements, its value in the result Map will be obtained by calling the downstream collector's supplier function and then applying the finisher function. Type Parameters: T - the type of the input elements A - the intermediate accumulation type of the downstream collector D - the result type of the downstream reduction

Comments
  • What's at.getKey, might be a typo there with a missing ()
  • I suggest using orElse(Collections.emptyMap()) instead, as there is no need to instantiate a new HashMap (and the groupingBy collector without a map supplier doesn’t guaranty to produce a HashMap, so the caller should not assume it).
  • Nice! I'd only suggest orElseGet(HashMap::new) instead of orElse(new HashMap<>()) to make it a little bit cleaner.
  • orElse(HashMap::new) wouldn't compiler either...made an edit for the same.
  • @nullpointer It was supposed to be orElseGet instead of orElse. I made the proper edit.
  • @TomaszLinkowski Well for an initialization of a HashMap I don't think orElse and orElseGet would make difference. But still, both of them should execute just fine.
  • @nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.