代码之家  ›  专栏  ›  技术社区  ›  Coder-Man

如何将map < String、人>转换为map <字符串、整数>在Java流中收集?

  •  4
  • Coder-Man  · 技术社区  · 6 年前

    假设你有一个名单,罗伯茨,保罗,理查兹等,这些人按名字分组 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<Person> 进入之内 List<Integer>
    • 在这些列表中查找最大整数。

    我在想怎么做:

    • 按名称分组到 map<string,list<person>>
    • 在每个组名中查找最年长的人,获取 map<string,person>
    • 转换 映射<字符串,个人> 进入之内 映射<字符串,整数> . 我想在GroupingBy、Reducing和Mapping的链中做所有这些。

    这是“伪代码”:

    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*/)));
    

    我怎样才能做到这一点?

    3 回复  |  直到 6 年前
        1
  •  3
  •   Ravindra Ranwala    6 年前

    如果你真的想用 groupingBy 如问题陈述中所述,您仍然可以这样做:

    final Map<String, Integer> oldestPersonByName = people.stream()
            .collect(Collectors.groupingBy(Person::getName, Collectors.reducing(0, Person::getAge, Integer::max)));
    

    对于约简,必须传递一个标识元素、映射函数和一个用于约简的二进制运算符,即 max 在这种情况下。

        2
  •  4
  •   Misha    6 年前

    使用 3-argument version of toMap collector :

    people.stream().collect(toMap(
            Person::getName, 
            Person::getAge, 
            Integer::max
        ));
    
        3
  •  2
  •   Radiodef    6 年前

    我想应该是这样的 maxBy 而不是 reducing .

    people.stream().collect(
        groupingBy(
            Person::getName,
            collectingAndThen(
                maxBy(Comparator.comparing(Person::getAge)),
                (Optional<Person> max) -> max.get().getAge()
            )
        )
    );