java8 分组和排序

523 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

java8 分组和排序

文本介绍了java8 lambada表达式用于多字段排序和分组的使用场景

1 拼接分组key


Map<String, Long> countMap = records.stream()
.collect(Collectors.groupingBy(o -> o.getProductType() + "_" + o.getCountry(), Collectors.counting()));

2 多字段分组 链式收集器 chain collectors

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




Map<String, Map<Integer, List<Person>>> map = people.collect(Collectors.groupingBy(Person::getName,
        Collectors.groupingBy(Person::getAge));
//获取结果2级map   map.get("Fred").get(18);


//超过2级的嵌套分组  https://xpadro.com/2016/02/multi-level-grouping-with-streams.html  

public void threeLevelGrouping(List<Person> persons) {
    final Map<String, Map<String, Map<String, List<Person>>>> personsByCountryCityAndPetName = persons.stream().collect(
            groupingBy(Person::getCountry,
                groupByCityAndPetName()
            )
    );
 
    System.out.println("Persons whose pet is named 'Max' and live in NY: " +
        personsByCountryCityAndPetName.get("USA").get("NYC").get("Max").size());
}
}




private Collector<Person, ?, Map<String, Map<String, List<Person>>>> groupByCityAndPetName() {
    return groupingBy(Person::getCity, groupingBy(p -> p.getPet().getName()));
}
}


3 在jdk14 后可以使用record


第三种选择是定义一个代表分组的类。这可以在Person内部,重写必要的hashcode 和equase 


class Person {
    public static class NameAge {
        public NameAge(String name, int age) {
            ...
        }
        // must implement equals and hash function
    }

    public NameAge getNameAge() {
        return new NameAge(name, age);
    }
}


class Person {
    record NameAge(String name, int age) { }
    public NameAge getNameAge() {
        return new NameAge(name, age);
    }
}
}

//使用方法
Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));
map.get(new NameAge("Fred", 18));

4 利用函数来生成组合key


Function<Person, List<Object>> compositeKey = personRecord ->
    Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());
Map<Object, List<Person>> map =
people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));


5 利用LIst 或数组 Ararys.asList() 【推荐使用】

Function<String, List> classifier = (item) -> List.of(
    item.getFieldA(),
    item.getFieldB(),
    Optional.ofNullable(item.getFieldC())
)
);




Map<List, List<Item>> grouped = items.stream()
    .collect(Collectors.groupingBy(classifier));

Map<Object, Long> M = LON.stream().collect(
            Collectors.groupingBy(p
                    -> Arrays.asList(p.getDatum(), p.getPerson().getIdfirm(), p.getIdProduct()),
                    Collectors.counting()));


6 多字段排序 【重要】


//参考 https://howtodoinjava.com/java8/sort-stream-multiple-fields/ 

//first name comparator
Comparator<Employee> compareByFirstName = Comparator.comparing( Employee::getFirstName );
 
//last name comparator
Comparator<Employee> compareByLastName = Comparator.comparing( Employee::getLastName );
 
//Compare by first name and then last name (multiple fields)
Comparator<Employee> compareByFullName = compareByFirstName.thenComparing(compareByLastName);
 
//Using Comparator - pseudo code
list.stream().sorted( comparator ).collect();


7 参考文档

stackoverflow.com/questions/2…

www.cnblogs.com/winner-0715…

www.baeldung.com/java-groupi… 【经典】

grokonez.com/java/java-8… 【经典】

howtodoinjava.com/java8/sort-…

xpadro.com/2016/02/mul…