假设你有一个人的列表,罗伯茨,保罗,理查兹等等,这些人按名字分组到Map<String, List<Person>>
中。你想找最年长的保罗,罗伯特,等等。你可以这样做:
public static void main(String... args) {
List<Person> people = Arrays.asList(
new Person(23, "Paul"),
new Person(24, "Robert"),
new Person(32, "Paul"),
new Person(10, "Robert"),
new Person(4, "Richard"),
new Person(60, "Richard"),
new Person(9, "Robert"),
new Person(26, "Robert")
);
Person dummy = new Person(0, "");
var mapping = people.stream().collect(groupingBy(Person::getName, reducing(dummy, (p1, p2) -> p1.getAge() < p2.getAge() ? p2 : p1)));
mapping.entrySet().forEach(System.out::println);
}
比方说,我想以Map<String, Integer>
而不是Map<String, Person>
的形式获得一个映射,我可以这样做:
var mapping = people.stream().collect(groupingBy(Person::getName, mapping(Person::getAge, reducing(0, (p1, p2) -> p1 < p2 ? p2 : p1))));
上面的步骤是:
Map<String/*Name*/, List<Person>>
List<Integer>
我想知道该怎么做:
Map<String, List<Person>>
Map<String, Person>
Map<String, Person>
转换为Map<String, Integer>
。我想在groupingBy's链中完成所有这些操作,减少‘s和And’s。这是“伪代码”:
var mapping = people.stream().collect(groupingBy(Person::getName, reducing(dummy, (p1, p2) -> p1.getAge() < p2.getAge() ? p2 : p1 /*, have to write some other collector factory method here*/)));
我如何才能做到这一点?
发布于 2018-05-30 10:47:27
如果你真的想像问题陈述中提到的那样使用groupingBy
,你仍然可以这样做:
final Map<String, Integer> oldestPersonByName = people.stream()
.collect(Collectors.groupingBy(Person::getName, Collectors.reducing(0, Person::getAge, Integer::max)));
对于reduce,您必须传递一个标识元素、映射函数和一个用于reduce的二元运算符,在本例中为max
。
发布于 2018-05-30 08:29:06
使用3-argument version of toMap
collector可以更直接地完成此操作
people.stream().collect(toMap(
Person::getName,
Person::getAge,
Integer::max
));
发布于 2018-05-30 08:06:54
我认为它会像下面这样,同样使用maxBy
而不是reducing
。
people.stream().collect(
groupingBy(
Person::getName,
collectingAndThen(
maxBy(Comparator.comparing(Person::getAge)),
(Optional<Person> max) -> max.get().getAge()
)
)
);
https://stackoverflow.com/questions/50594490
复制相似问题