Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fastest way to convert key value pairs to grouped by key objects map using java 8 stream

Model:

public class AgencyMapping {
    private Integer agencyId;
    private String scoreKey;
}

public class AgencyInfo {
    private Integer agencyId;
    private Set<String> scoreKeys;
}

My code:

List<AgencyMapping> agencyMappings;
 Map<Integer, AgencyInfo> agencyInfoByAgencyId = agencyMappings.stream()
            .collect(groupingBy(AgencyMapping::getAgencyId,
                    collectingAndThen(toSet(), e -> e.stream().map(AgencyMapping::getScoreKey).collect(toSet()))))
            .entrySet().stream().map(e -> new AgencyInfo(e.getKey(), e.getValue()))
            .collect(Collectors.toMap(AgencyInfo::getAgencyId, identity()));

Is there a way to get the same result and use more simpler code and faster?

like image 657
Jack Avatar asked Mar 25 '18 14:03

Jack


People also ask

How to group by using Java 8?

In Java 8, you retrieve the stream from the list and use a Collector to group them in one line of code. It's as simple as passing the grouping condition to the collector and it is complete. By simply modifying the grouping condition, you can create multiple groups.

What is a flatMap in Java 8?

In Java 8 Streams, the flatMap() method applies operation as a mapper function and provides a stream of element values. It means that in each iteration of each element the map() method creates a separate new stream. By using the flattening mechanism, it merges all streams into a single resultant stream.

How to get the key-value pair of a hashmap in Java?

Thus, in most cases, you'll want to get the key-value pair together. The entrySet () method returns a set of Map.Entry<K, V> objects that reside in the map. You can easily iterate over this set to get the keys and their associated values from a map. Let's populate a HashMap with some values:

How do I get the key-value pair of a map?

Thus, in most cases, you'll want to get the key-value pair together. The entrySet () method returns a set of Map.Entry<K, V> objects that reside in the map. You can easily iterate over this set to get the keys and their associated values from a map.

How to handle duplicate keys in Java 8 streams?

Java 8 Streams provide Collectors.toMap (keyMapper, valueMapper, mergeFunction) overloaded method where you can specify which value to consider when duplicate key issue occur. Let’s collect a Map having user name as a key, merge function indicate that keep the old value for the same key:-

What is the difference between keymapper and valuemapper in Java?

The Collectors.toMap () method takes two parameters as the input: KeyMapper: This function is used for extracting keys of the Map from stream value. ValueMapper: This function used for extracting the values of the map for the given key.


Video Answer


1 Answers

You can simplify the call to collectingAndThen(toSet(), e -> e.stream().map(AgencyMapping::getScoreKey).collect(toSet())))) with a call to mapping(AgencyMapping::getScoreKey, toSet()).

Map<Integer, AgencyInfo> resultSet = agencyMappings.stream()
                .collect(groupingBy(AgencyMapping::getAgencyId,
                        mapping(AgencyMapping::getScoreKey, toSet())))
                .entrySet()
                .stream()
                .map(e -> new AgencyInfo(e.getKey(), e.getValue()))
                .collect(toMap(AgencyInfo::getAgencyId, identity()));

A different way to see it using a toMap collector:

Map<Integer, AgencyInfo> resultSet = agencyMappings.stream()
                .collect(toMap(AgencyMapping::getAgencyId, // key extractor
                        e -> new HashSet<>(singleton(e.getScoreKey())), // value extractor
                        (left, right) -> { // a merge function, used to resolve collisions between values associated with the same key
                            left.addAll(right);
                            return left;
                        }))
                .entrySet()
                .stream()
                .map(e -> new AgencyInfo(e.getKey(), e.getValue()))
                .collect(toMap(AgencyInfo::getAgencyId, identity()));

The latter example is arguably more complicated than the former. Nevertheless, your approach is pretty much the way to go apart from using mapping as opposed to collectingAndThen as mentioned above.

Apart from that, I don't see anything else you can simplify with the code shown.

As for faster code, if you're suggesting that your current approach is slow in performance then you may want to read the answers here that speak about when you should consider going parallel.

like image 165
Ousmane D. Avatar answered Oct 17 '22 17:10

Ousmane D.