I need to create Map<String, String>
from List<Person>
using Stream API.
persons.stream()
.collect(Collectors
.toMap(Person::getNationality, Person::getName, (name1, name2) -> name1)
But in the above case, I want to resolve conflict in name attribute by using Person's age. is there any way to pass merge function something around the lines (age1, age2) -> // if age1 is greater than age2 return name1, else return name2
?
Collectors.toMap() with Mapper and Merge FunctionsIt's input are two values that is the two values for which keyMapper returned the same key, and merges those two values into a single one.
Java Collectors. Collectors is a final class that extends Object class. It provides reduction operations, such as accumulating elements into collections, summarizing elements according to various criteria, etc. Java Collectors class provides various methods to deal with elements.
Method 1: Using Collectors.toMap() Function 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.
To select a person based on its age, you need the Person
instance to query the age. You cannot reconstitute the information after you mapped the Person
to a plain name String
.
So you have to collect the persons first, to be able to select the oldest, followed by mapping them to their names:
persons.stream()
.collect(Collectors.groupingBy(Person::getNationality, Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparingInt(Person::getAge)),
o -> o.get().getName())));
If you don't want to use a helper data structure, it is possible if you first keep your Person info and perform the merge based on it and apply the mapping afterwards:
public void test() {
final List<Person> persons = new ArrayList<>();
final BinaryOperator<Person> mergeFunction =
(lhs, rhs) -> lhs.getAge() > rhs.getAge() ? lhs : rhs;
final Function<Person, String> mapFunction = Person::getName;
final Map<String, String> personNamesByNation =
persons.stream()
.collect(
Collectors.groupingBy(Person::getNation, // KeyMapper Person.getNation: Map<String, List<Person>>
Collectors.collectingAndThen(
Collectors.collectingAndThen(
Collectors.reducing(mergeFunction), // Merge Persons into single value via merge function: Map<String, Optional<Person>>
Optional::get), // unwrap value: Map<String, Person>
mapFunction))); // apply map function afterwards: Map<String, String>
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With