java 根据对象某个属性进行去重

java 根据对象某个属性进行去重

    • 前言
    • 方式一
      • 1.1 根据name去重
      • 1.2 获取list中所有的name并去重
      • 1.3 过滤list中年龄大于11的人
      • 1.4 根据年龄进行分组
      • 1.5 list转map
      • 1.6:排序
    • 方式二
      • 2.1 根据age去重
    • 方式三
      • 3.1 利用Collectors.toCollection去重

前言

在开发中可能会遇到很多需要去重的情况,比如Person对象有name跟age两个属性,需要根据age进行去重。本文主要是基于java8提供的stream流进行处理。

方式一

1.1 根据name去重

public class test {
    public static void main(String[] args) {
        List<Person> ps=new ArrayList<>();
        ps.add(new Person(11,"tom"));
        ps.add(new Person(11,"张三"));
        ps.add(new Person(12,"tom"));
        ps.add(new Person(11,"tom"));
        //根据name进行去重
        List<Person> list = ps.stream().collect(
                Collectors.collectingAndThen(Collectors.toCollection(
                        () -> new TreeSet<>(Comparator.comparing(p -> p.getName()))), ArrayList::new)
        );
        list.forEach(System.out::println);
        System.out.println("-----------");
        //根据name与age进行去重
        List<Person> list1 = ps.stream().collect(
                Collectors.collectingAndThen(Collectors.toCollection(
                        () -> new TreeSet<>(Comparator.comparing(p -> p.getName()+";"+p.getAge()))), ArrayList::new)
        );
        list1.forEach(System.out::println);
    }
}
@Data
class Person{
    String name;
    int age;
    Person(int age,String name){
        this.name=name;
        this.age=age;
    }
}

执行结果

Person(name=tom, age=11)
Person(name=张三, age=11)
-----------
Person(name=tom, age=11)
Person(name=tom, age=12)
Person(name=张三, age=11)

1.2 获取list中所有的name并去重

//获取list中所有的name
List<String> list=ps.stream().map(Person::getName).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
list.forEach(System.out::println);

执行结果

tom
张三

1.3 过滤list中年龄大于11的人

List<Person> list=ps.stream().filter(p -> p.getAge()>11).collect(Collectors.toList());
list.forEach(System.out::println);

执行结果

Person(name=tom, age=12)

1.4 根据年龄进行分组

Map<Integer,List<Person>> map=ps.stream().collect(Collectors.groupingBy(Person::getAge));
System.out.println(map.get(11));

执行结果:

[Person(name=tom, age=11), Person(name=张三, age=11), Person(name=tom, age=11)]

根据类型分组,并分别计算每组的年龄总和

public class test {
    public static void main(String[] args) {
        List<User> list=new ArrayList<>();
        list.add(new User("张三",20,"A"));
        list.add(new User("tom",21,"A"));
        list.add(new User("jack",22,"B"));
        //stream根据年龄字段计算总和
        int ageSum= list.stream().mapToInt(User::getAge).sum();
        //根据A,B分组,并分别计算每组的年龄总和
        List<User> list1=list.stream()
                .collect(Collectors.groupingBy(User::getType))
                .entrySet()
                .stream().map((entry)-> {
                    String key=entry.getKey();
                    List<User> typeList=entry.getValue();
                    int sum=typeList.stream().mapToInt(User::getAge).sum();
                    return new User("A",sum,key);
                })
                // 根据age倒序排序
                .sorted(Comparator.comparing(User::getAge).reversed())
                .collect(Collectors.toList());
        System.out.println(list1);
    }
}
@Data
class User{
    String username;
    Integer age;
    String type;
    User(String username,Integer age,String type){
        this.username=username;
        this.age=age;
        this.type=type;
    }
}

执行结果:

[User(username=A, age=41, type=A), User(username=A, age=22, type=B)]

1.5 list转map

list转map若key重复,则需要指定重复策略(如重复时新的替换旧的),否则会报错。

List<Person> ps=new ArrayList<>();
ps.add(new Person(11,"tom"));
ps.add(new Person(11,"张三"));

// 将list转换为 map,注意name作为 key 不能重复,应先做去重处理,否则会报错
Map<String, Integer> map = ps.stream().collect(Collectors.toMap(Person::getName, Person::getAge));
map.forEach((s, i) -> System.out.println(s+"|"+i));
// 用 name 做 key 将 List 转成 Map
Map<String, Person> map1 = ps.stream().collect(Collectors.toMap(Person::getName, item -> item));
//将list转成Map, 若key重复,则使用旧的,解决key重复报错的问题
        Map<String, Person> map2 = ps.stream().collect(Collectors.toMap(Person::getName, Function.identity(), (oldValue, newValue) -> oldValue));
//根据name进行去重,转换为Map,然后再转换为list
ps.stream().collect(Collectors.toMap(Person::getName, Function.identity(), (oldValue, newValue) -> oldValue))
       .values()
       .stream();
for (Person p : ps) {
   System.out.println(p);
} 

执行结果

张三|11
tom|11

1.6:排序

public class test {
    public static void main(String[] args) {
        List<Person> ps=new ArrayList<>();
        ps.add(new Person(11,"tom"));
        ps.add(new Person(11,"张三"));
        ps.add(new Person(12,"tom"));
        ps.add(new Person(11,"tom"));

        // 按照年龄从高到低排序
        // 方式一
        ps.sort((o1, o2)
                -> o1.getAge() == null ? 1 : (o2.getAge() == null ? -1 : o2.getAge().compareTo(o1.getAge())));
        System.out.println(ps);
        // 方式二
        ps.sort(Comparator.comparing(Person::getAge, (o1, o2)
                -> o1 == null ? 1 : (o2 == null ? -1 : o2.compareTo(o1))));
        System.out.println(ps);
        // 方式三 (age 字段不能为 null, null 会导致排序失败)
        ps.sort(Comparator.comparing(Person::getAge).reversed());
        System.out.println(ps);
        // 先按照年龄排序,再按照姓名从高到低排序
        ps.sort(Comparator.comparing(Person::getAge, (o1, o2)
                -> o1 == null ? 1 : (o2 == null ? -1 : o1.compareTo(o2))).thenComparing((o1, o2)
                -> o1.getName() == null ? 1 : (o2.getName() == null ? -1 : o2.getName().compareTo(o1.getName()))));
        System.out.println(ps);
    }
}
@Data
class Person{
    String name;
    Integer age;
    Person(Integer age,String name){
        this.name=name;
        this.age=age;
    }
}

执行结果

[Person(name=tom, age=12), Person(name=tom, age=11), Person(name=张三, age=11), Person(name=tom, age=11)]
[Person(name=tom, age=12), Person(name=tom, age=11), Person(name=张三, age=11), Person(name=tom, age=11)]
[Person(name=tom, age=12), Person(name=tom, age=11), Person(name=张三, age=11), Person(name=tom, age=11)]
[Person(name=张三, age=11), Person(name=tom, age=11), Person(name=tom, age=11), Person(name=tom, age=12)]

方式二

2.1 根据age去重

List<Person> ps=new ArrayList<>();
ps.add(new Person(11,"tom"));
ps.add(new Person(11,"张三"));
ps.add(new Person(12,"tom"));
ps.add(new Person(11,"tom"));
ps.stream()
//Collectors.toMap(Person::getAge 或者这样写 Collectors.toMap(m -> m.getUserId()
.collect(Collectors.toMap(Person::getAge,
      Function.identity(), (oldValue, newValue) -> oldValue))
.values()
.stream()
.forEach(System.out::println); //打印

执行结果:

Person(name=tom, age=11)
Person(name=tom, age=12)

代码讲解
ps.stream()
.collect(Collectors.toMap(Person::getAge,
Function.identity(), (oldValue, newValue) -> oldValue))
如上代码返回的是Map集合,所以list可以与map进行转换,若key重复,则使用旧的值。

方式三

3.1 利用Collectors.toCollection去重

List<Person> ps=new ArrayList<>();
ps.add(new Person(11,"tom"));
ps.add(new Person(11,"张三"));
ps.add(new Person(12,"tom"));
ps.add(new Person(11,"tom"));
ps.stream()
 .collect(Collectors.toCollection(() ->
         new TreeSet<>(Comparator.comparing(Person::getName))))
 .stream()
 .forEach(System.out::println); //打印

利用TreeSet原理去重,TreeSet内部使用的是TreeMap,使用指定Comparator比较元素,如果元素相同,则新元素代替旧元素,如果不想要返回TreeSet类型,那也可以使用Collectors.collectingAndThen转换成ArrayList,也可以用new ArrayList(set),原理一样,如下:

List<Person> list = ps.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()
          -> new TreeSet<>(Comparator.comparing(Person::getName))), ArrayList::new));

** 如果想根据多个去重,可以将上述方法中的Comparator.comparing(Person::getName))修改为Comparator.comparing(p -> p.getName() +“;” + p.getAge() )) 这样就是根据两个字段去重,中间的 ; 作用就是为了增加辨识度,也可以不加这个 ; ,无论多少个字段去重只用在这里用+连接就可以了

你可能感兴趣的:(java,java,stream)