在Java 8中按多个字段名称分组

我找到了通过POJO中的某些字段名称对对象进行分组的代码。以下是该代码:


public class Temp {


    static class Person {


        private String name;

        private int age;

        private long salary;


        Person(String name, int age, long salary) {


            this.name = name;

            this.age = age;

            this.salary = salary;

        }


        @Override

        public String toString() {

            return String.format("Person{name='%s', age=%d, salary=%d}", name, age, salary);

        }

    }


    public static void main(String[] args) {

        Stream<Person> people = Stream.of(new Person("Paul", 24, 20000),

                new Person("Mark", 30, 30000),

                new Person("Will", 28, 28000),

                new Person("William", 28, 28000));

        Map<Integer, List<Person>> peopleByAge;

        peopleByAge = people

                .collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p, toList())));

        System.out.println(peopleByAge);

    }

}

输出是(正确的):


{24=[Person{name='Paul', age=24, salary=20000}], 28=[Person{name='Will', age=28, salary=28000}, Person{name='William', age=28, salary=28000}], 30=[Person{name='Mark', age=30, salary=30000}]}

但是,如果我想按多个字段分组怎么办?在该POJO中groupingBy()实现equals()方法后,我显然可以在该方法中传递一些POJO,但是是否还有其他选择,例如我可以对给定POJO中的多个字段进行分组?


例如,在这里,我想按姓名和年龄分组。


SMILET
浏览 4027回答 3
3回答

长风秋雁

您在这里有一些选择。最简单的方法是链接您的收藏家:Map<String, Map<Integer, List<Person>>> map = people&nbsp; &nbsp; .collect(Collectors.groupingBy(Person::getName,&nbsp; &nbsp; &nbsp; &nbsp; Collectors.groupingBy(Person::getAge));然后,要使用18岁的年轻人Fred的清单,您可以使用:map.get("Fred").get(18);第二种选择是定义一个代表分组的类。这可以在Person内部:class Person {&nbsp; &nbsp; public static class NameAge {&nbsp; &nbsp; &nbsp; &nbsp; public NameAge(String name, int age) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // must implement equals and hash function&nbsp; &nbsp; }&nbsp; &nbsp; public NameAge getNameAge() {&nbsp; &nbsp; &nbsp; &nbsp; return new NameAge(name, age);&nbsp; &nbsp; }}然后,您可以使用:Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));并搜索map.get(new NameAge("Fred", 18));最后,如果您不想实现自己的组类,那么周围的许多Java框架都有一个pair专门用于此类事情的类。例如:apache commons pair如果您使用这些库之一,则可以将地图的名称和年龄配对:Map<Pair<String, Integer>, List<Person>> map =&nbsp; &nbsp; people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));并使用:map.get(Pair.of("Fred", 18));我个人真的不喜欢这些元组库。它们似乎与良好的OO设计完全相反:它们隐藏意图而不是公开意图。话虽如此,您可以通过定义自己的分组类来组合后两个选项,而仅通过扩展即可实现Pair-从而节省了很多定义equals等工作,并且将元组的使用隐藏为任何其他便捷的实现细节其他集合。祝好运。

蓝山帝景

这里看一下代码:您可以简单地创建一个功能,让它为您完成工作,一种功能样式!Function<Person, List<Object>> compositeKey = personRecord ->&nbsp; &nbsp; Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());现在,您可以将其用作地图:Map<Object, List<Person>> map =people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));干杯!

慕斯王

该groupingBy方法具有的第一个参数是Function<T,K>:@param <T>输入元素的类型@param <K>键的类型如果在您的代码中将lambda替换为匿名类,则可以看到以下内容:people.stream().collect(Collectors.groupingBy(new Function<Person, int>() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public int apply(Person person) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return person.getAge();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }));刚才更改输出参数<K>。例如,在这种情况下,我使用了org.apache.commons.lang3.tuple中的pair类按名称和年龄进行分组,但是您可以根据需要创建自己的类以过滤组。people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public YourFilter apply(Person person) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Pair.of(person.getAge(), person.getName());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }));最后,用lambda back替换后,代码如下所示:Map<Pair<Integer,String>, List<Person>> peopleByAgeAndName = people.collect(Collectors.groupingBy(p -> Pair.of(person.getAge(), person.getName()), Collectors.mapping((Person p) -> p, toList())));
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java