[英]Stream for each key of map entry, containing list as a value
I have a map of <String, List<T>>
and want to create a stream for each entry's value, in which I will be able to find the maximum element of List<T>
and after that map <String, List<T>>
to <String, T>
. 我有一个
<String, List<T>>
的映射,并且想为每个条目的值创建一个流,在其中我将能够找到List<T>
的最大元素,然后在该映射<String, List<T>>
到<String, T>
。 How do I do that? 我怎么做? Spent over 3 hours trying to figure out.
花了3多个小时试图找出答案。
Update Forgot to tell that I was asked to do it two ways: with Collector.toMap
and without it and I'm most curious about the way without it. 更新忘了告诉我,我被要求这样做两种方式:使用
Collector.toMap
和不使用它,我对不使用它的方式最好奇。
The step where I'm stuck is: 我遇到的问题是:
employees.stream()
.flatMap(e -> e.getJobHistory().stream()
.map(j -> new PersonPositionDuration(e.getPerson(), j.getPosition(), j.getDuration())))
.collect(Collectors.groupingBy(p -> p.getPosition()))
.entrySet().
employees
is a List of Employee
object, each has jobHistory
property, which is a List
as well and each entry of it has employer
property, which is String
. employees
是一个List Employee
对象,每个人都有jobHistory
属性,它是一个List
,以及和它的每一项都有employer
的财产,这是String
。 So I turn this List<Employee>
to a Map<String, List<PersonPositionDuration>>
, where key is emploer and value is a class, containing info about a person and how long he was working as someone for this emploer. 因此,我将这个
List<Employee>
转换为Map<String, List<PersonPositionDuration>>
,其中的键是emploer,value是一个类,其中包含有关一个人的信息以及他为该雇主工作的时间。 Keys aren't unique. 键不是唯一的。
What I want to do is to find a PersonPositionDuration
with a longest duration, we can get it by getDuration()
. 我想做的是找到一个持续时间最长的
PersonPositionDuration
,我们可以通过getDuration()
获得它。 So what do I do after I get and entry set? 那么,我在获得并设置条目后该怎么办?
Also, I am adviced to use Collectors.maxBy
and Collectors.collectingAndThen
, but I have no idea how to do it. 另外,建议我使用
Collectors.maxBy
和Collectors.collectingAndThen
,但是我不知道该怎么做。
Assuming T
implements Comparable
(because you need to be able to calculate the maximum of two values) you can wrap your code in a method such as this: 假设
T
实现了Comparable
(因为您需要能够计算两个值中的最大值),则可以将代码包装在这样的方法中:
public <T extends Comparable<T>> Map<String, T> convert(Map<String, List<T>> data) {
// variable for readability, you can return it right away if you prefer
Map<String, T> result = data.entrySet().stream().collect(Collectors.toMap(
// for each key in our map...
e -> e.getKey(),
// ... we determine the maximum and store it as new value
e -> Collections.max(e.getValue())
));
return result;
}
It creates a Set<Map.Entry<String, List<T>>>
of which you can create a Stream
which is converted into a Map<String, T>
by converting the value type using Collections.max()
which uses Comparable.compareTo
to compare two objects and determine which one is greater than the other. 它创建一个
Set<Map.Entry<String, List<T>>>
,您可以创建一个Stream
,该Stream
可以通过使用Comparable.compareTo
Collections.max()
转换值类型来转换为Map<String, T>
Comparable.compareTo
比较两个对象并确定哪个对象大于另一个对象。 Note that you can just use it as is for boxed types like Integer
or Double
(and many more) as they all implement Comparable
. 请注意,由于它们都实现了
Comparable
,因此可以像Integer
或Double
(还有更多)之类的盒装类型一样直接使用它。
If your map
is of type <String, List<Integer>>
it can be done as 如果您的
map
类型为<String, List<Integer>>
则可以通过以下方式完成
Map<String, List<Integer>> map = new HashMap<>();
map.put("a", Arrays.asList(5, 3, 7));
map.put("b", Arrays.asList(1, 5));
map.put("c", Arrays.asList(45, 2));
map.put("d", Arrays.asList(4, 6, 2, 34));
map.entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> {
return entry.getValue().stream().max(Integer::compareTo).orElse(0);
}));
output : 输出:
{a=7, b=5, c=45, d=34}
You can modify the entry.getValue().stream().max(Integer::compareTo).orElse(0)
with the comparator for Type T
or your class Type. 您可以使用
T
型比较器或类Type的比较器修改entry.getValue().stream().max(Integer::compareTo).orElse(0)
。
It is not totally clear what you want to achieve or how your data structure looks like. 尚不清楚要实现什么或数据结构如何。 What you wrote and the code you showed doesn't match together.
您编写的内容与显示的代码不一致。 They achieve very different things.
他们实现了截然不同的事情。
But you wished for a solution by using Collectors.maxBy
and without Collectors.toMap
. 但是你用希望的解决方案
Collectors.maxBy
并没有Collectors.toMap
。 The other answers didn't provide such a solution. 其他答案没有提供这样的解决方案。 Therefore I will try to give one.
因此,我将尝试给出一个。
Your Data: 您的资料:
As your data structure I assume you have employers which each employ multiple employees. 作为您的数据结构,我假设您有每个雇用多名雇员的雇主。 Every employee has some personal information, the position he works/ed in and the duration he worked in this position until know.
每位员工都有一些个人信息,他所从事的工作/担任过的职位以及他在该职位上的工作期限,直到知道为止。
For example (Map employerEmployeeMap ): 例如(Map ownerEmployeeMap ):
CompanyA: [{Max, Developer, 5.4}, {Mari, Designer, 6.8}, {Paul, Manager, 1.2}]
CompanyB: [{Lea, CEO, 7.1}, {Tom, Admin, 4.5}, {Ria, Marketing, 0.4}]
CompanyC: [{Alex, Secretary, 1.5}, {Lisa, Developer, 3.3}, {Mia, Developer, 2.7}]
What you want to achieve: 您想要实现的目标:
You want to have the PersonPositionDuration
with the longest duration. 您想使
PersonPositionDuration
具有最长的持续时间。 I wasn't sure if you want only the person with the longest duration over all employers or per each employer. 我不确定您是否只希望在所有雇主中或每个雇主中任职时间最长的人。 Therefore I will provide multiple solutions.
因此,我将提供多种解决方案。
Solution with maxBy maxBy解决方案
If you only want the person with the longest duration over all employers you can just iterate over the employees and get the one with the highest duration: 如果您只希望在所有雇主中任职时间最长的人,则可以对雇员进行迭代并获得其任职时间最长的人:
Optional<PersonPositionDuration> maxDurationPerson = employerEmployeeMap.values().stream()
.flatMap(List::stream)
.collect(maxBy(comparing(PersonPositionDuration::getDuration)));
This would be equal to: 这将等于:
Optional<PersonPositionDuration> maxDurationPerson = employerEmployeeMap.values().stream()
.flatMap(List::stream)
.max(comparing(PersonPositionDuration::getDuration));
Result: {Lea, CEO, 7.1}
结果:
{Lea, CEO, 7.1}
If you want only the person with the highest duration but do not want to lose the employer information: 如果您只想要持续时间最长的人,而又不想失去雇主信息:
Optional<Pair<String, PersonPositionDuration>> maxDurationPersonCompany = employerEmployeeMap.entrySet().stream()
.flatMap(entry -> entry.getValue().stream().map(p -> new Pair<>(entry.getKey(), p)))
.max(comparing(entry -> entry.getValue().getDuration()));
Result: CompanyB: {Lea, CEO, 7.1}
结果:
CompanyB: {Lea, CEO, 7.1}
If you want the person with the highest duration for every company you can do the following: 如果您希望每个公司的工作时间最长的人,则可以执行以下操作:
Map<String, Optional<Pair<String, PersonPositionDuration>>> maxDurationPerCompany = employerEmployeeMap.entrySet().stream()
.flatMap(entry -> entry.getValue().stream().map(p -> new Pair<>(entry.getKey(), p)))
.collect(groupingBy(Pair::getKey, maxBy(comparing(entry -> entry.getValue().getDuration()))));
Result: 结果:
CompanyA: {Mari, Designer, 6.8}
CompanyB: {Lea, CEO, 7.1}
Companyc: {Lisa, Developer, 3.3}
I hope this covers your question and your need. 我希望这能涵盖您的问题和需求。 If not, if something is missing or of if something is unclear, please feel free to comment.
如果不是,如果缺少某些内容或不清楚的内容,请随时发表评论。
Full working example: 完整的工作示例:
import javafx.util.*;
import java.util.*;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.*;
public class Main {
public static void main(String[] args) {
class PersonPositionDuration {
private final String person;
private final String position;
private final Double duration;
public PersonPositionDuration(String person, String position, Double duration) {
this.person = person;
this.position = position;
this.duration = duration;
}
public Double getDuration() {
return duration;
}
}
Map<String, List<PersonPositionDuration>> employerEmployeeMap = new HashMap<>();
employerEmployeeMap.put("CompanyA", Arrays.asList(new PersonPositionDuration("Max", "Developer", 5.4), new PersonPositionDuration("Mari", "Designer", 6.8), new PersonPositionDuration("Paul", "Manager", 1.2)));
employerEmployeeMap.put("CompanyB", Arrays.asList(new PersonPositionDuration("Lea", "CEO", 7.1), new PersonPositionDuration("Tom", "Admin", 4.5), new PersonPositionDuration("Ria", "Marketing", 0.4)));
employerEmployeeMap.put("CompanyC", Arrays.asList(new PersonPositionDuration("Alex", "Secretary", 1.5), new PersonPositionDuration("Lisa", "Developer", 3.3), new PersonPositionDuration("Mia", "Developer", 2.7)));
Optional<PersonPositionDuration> maxDurationPerson = employerEmployeeMap.values()
.stream()
.flatMap(List::stream)
.max(comparing(PersonPositionDuration::getDuration));
Optional<Pair<String, PersonPositionDuration>> maxDurationPersonCompany = employerEmployeeMap.entrySet()
.stream()
.flatMap(entry -> entry.getValue()
.stream()
.map(p -> new Pair<>(entry.getKey(), p)))
.max(comparing(entry -> entry.getValue()
.getDuration()));
Map<String, Optional<Pair<String, PersonPositionDuration>>> maxDurationPerCompany = employerEmployeeMap.entrySet()
.stream()
.flatMap(entry -> entry.getValue()
.stream()
.map(p -> new Pair<>(entry.getKey(), p)))
.collect(groupingBy(Pair::getKey, maxBy(comparing(entry -> entry.getValue()
.getDuration()))));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.