流映射条目的每个键,包含列表作为值

时间:2016-12-22 22:58:02

标签: java java-8 java-stream

我有一张<String, List<T>>的地图,想要为每个条目的值创建一个流,我可以在其中找到List<T>的最大元素,然后在该地图<String, List<T>>之后到<String, T>。我怎么做?花了3个多小时才想出来。

更新 忘了说我被要求做两种方式:用Collector.toMap而没有它,我对没有它的方式感到最好奇。

我遇到的一步是:

employees.stream()
            .flatMap(e -> e.getJobHistory().stream()
                    .map(j -> new PersonPositionDuration(e.getPerson(), j.getPosition(), j.getDuration())))
            .collect(Collectors.groupingBy(p -> p.getPosition()))
            .entrySet().

employeesEmployee对象的列表,每个对象都有jobHistory属性,也是List,并且每个条目都有employer属性,String。所以我把这个List<Employee>变成Map<String, List<PersonPositionDuration>>,其中key是就业者,value是一个类,包含一个人的信息以及他作为这个雇员的人工作了多长时间。钥匙不是唯一的。

我想要做的是找到持续时间最长的PersonPositionDuration,我们可以通过getDuration()获取。那么在我获得和输入后我该怎么办?

此外,我建议使用Collectors.maxByCollectors.collectingAndThen,但我不知道该怎么做。

3 个答案:

答案 0 :(得分:3)

假设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;
}

创建Set<Map.Entry<String, List<T>>>,您可以使用Stream使用Map<String, T>转换值类型,将Collections.max()转换为Comparable.compareTo比较两个对象并确定哪个对象大于另一个。请注意,您可以像IntegerDouble(以及更多)一样使用它,因为它们都会实现Comparable

答案 1 :(得分:2)

如果您的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);
}));

输出

{a=7, b=5, c=45, d=34}

您可以使用类型entry.getValue().stream().max(Integer::compareTo).orElse(0)的比较器或类类型修改T

答案 2 :(得分:0)

您想要实现的目标或数据结构的外观并不完全清楚。你写的和你展示的代码不匹配。他们完成了截然不同的事情。

但您希望使用Collectors.maxBy而不使用Collectors.toMap来获得解决方案。其他答案没有提供这样的解决方案。因此,我会尝试给一个。

您的数据:

作为您的数据结构,我假设您有雇主,每个雇主雇用多名员工。每个员工都有一些个人信息,他工作/编辑的职位以及他在这个岗位上工作的时间,直到知道为止。

例如(Map employerEmployeeMap ):

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}]

您想要达到的目标:

您希望PersonPositionDuration的持续时间最长。我不确定你是否只想要所有雇主或每个雇主的持续时间最长的人。因此,我将提供多种解决方案。

使用maxBy解决方案

如果您只想要持续时间超过所有雇主的人,您可以迭代员工并获得持续时间最长的员工:

Optional<PersonPositionDuration> maxDurationPerson = employerEmployeeMap.values().stream()
                .flatMap(List::stream)
                .collect(maxBy(comparing(PersonPositionDuration::getDuration)));

这等于:

Optional<PersonPositionDuration> maxDurationPerson = employerEmployeeMap.values().stream()
                .flatMap(List::stream)
                .max(comparing(PersonPositionDuration::getDuration));

结果:{Lea, CEO, 7.1}

如果您只想要持续时间最长但不想丢失雇主信息的人:

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()));

结果:CompanyB: {Lea, CEO, 7.1}

如果您想要每个公司的持续时间最长的人,您可以执行以下操作:

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()))));

结果:

CompanyA: {Mari, Designer, 6.8}
CompanyB: {Lea, CEO, 7.1}
Companyc: {Lisa, Developer, 3.3}

我希望这能涵盖您的问题和您的需求。如果没有,如果缺少某些东西或者某些东西不清楚,请随时发表评论。

完整的工作示例:

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()))));
    }
}