• list去重+Java8-Stream distinct 根据list某个字段去重


    list去重 + Java8-Stream流操作List去重distinct、和指定字段去重

    新建一个list数组:

    List list = new ArrayList(); 
    list.add(26); 
    list.add(39); 
    list.add(39); 
    list.add(39); 
    list.add(39); 
    list.add(5); 
    list.add(40); 
    list.add(39); 
    list.add(25); 
    System.out.println(list); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    方法一:使用java8新特性stream进行List去重 【常用】

    注意:去重对象,他只能去重对象中所有字段都一样的,不能针对单个去重

    List newList = list.stream().distinct().collect(Collectors.toList()); 
    System.out.println(“java8新特性stream去重:”+newList); 
    list.add(39); 
    
    • 1
    • 2
    • 3

    方法三:set集合判断去重,不打乱顺序

    protected final <T> List<T> removeDuplicates(List<T> list) {
        return new ArrayList<>(new LinkedHashSet<>(list))
    }
    
    • 1
    • 2
    • 3

    Java8-Stream流操作List去重distinct、和指定字段去重

    方式一:Java8-Stream流操作List去重distinct、和指定字段去重

    stream的distinct去重方法,是根据 Object.equals,和 Object.hashCode这两个方法来判断是否重复的。
    所以我们可以利用这个特性 ,重写pojo的 Object.equals,和 Object.hashCode这两个方法,来实现。

    1、重写Book类的equals和hashCode方法,以name来判断比较是否相同,然后用stream的distinct方法来去重

    class Book {
        ...
     
        @Override
        public String toString() {
            return String.format("(%s,%s,%s)", id, name, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(createTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
        }
     
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Book book = (Book) o;
            return Objects.equals(name, book.name);
        }
    }
     
    List<Book> distinctNameBooks1 = books.stream().distinct().collect(Collectors.toList());
    System.out.println(distinctNameBooks1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    总结:通过重写equals和hashCode方法,按实际需求来比较,可直接使用stream的distinct方法去重,比较方便;有时对象类不方便或者不能修改,如它已实现好或者是引用的三方包不能修改,该方法不能灵活地按字段来去重。

    2、通过Collectors.collectingAndThen的Collectors.toCollection,里面用TreeSet在构造函数中指定字段

    一个字段去重

    List<ProjectInfoVo> vo = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(ProjectInfoVo.class));
    ArrayList<ProjectInfoVo> collect = vo.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(
                        Comparator.comparing(p -> p.getProjectId()))), ArrayList::new));
    
    • 1
    • 2
    • 3
    • 4

    多个字段去重

    List<ProjectInfoVo> vo = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(ProjectInfoVo.class));
    ArrayList<ProjectInfoVo> collect = vo.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(
                        Comparator.comparing(p -> p.getProjectId()+";"+p.getMember()))), ArrayList::new));
    
    • 1
    • 2
    • 3
    • 4

    总结:
    使用stream流提供的方法,代码很简洁,但不足是虽然实现了去重效果,但list里的顺序变化了,而有的场景需要保持顺序。

    3.自定义方法Comparator.comparing(p -> p.get***())

    自定义方法类——distinctByKey

    public class StreamUtils {
    
     
        public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
            Map<Object, Boolean> seen = new ConcurrentHashMap<>();
            return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    单个字段

    List<ProjectInfoVo> acceptances = vo.stream()
    	.filter(StreamUtils.distinctByKey(b -> b.getProjectId()))
    	.collect(Collectors.toList());
    
    • 1
    • 2
    • 3

    多个字段

    List<ProjectInfoVo> acceptances = vo.stream()
    	.filter(StreamUtils.distinctByKey(b -> b.getProjectId()))
    	.filter(StreamUtils.distinctByKey(b -> b.getMember()))
    	.collect(Collectors.toList());
    
    • 1
    • 2
    • 3
    • 4

    总结:通过封装定义一个去重方法,配合filter方法可灵活的按字段去重,保持了原列表的顺序,不足之处是内部定义了一个HashMap,有一定内存占用,并且多了一个方法定义。

    4、通过stream的filter方法来去重,不定义去重方法,在外面创建HashMap

    Map<Object, Boolean> map = new HashMap<>();
    List<Book> distinctNameBooks4 = books.stream().filter(i -> map.putIfAbsent(i.getName(), Boolean.TRUE) == null).collect(Collectors.toList());
    System.out.println(distinctNameBooks4);
    
    • 1
    • 2
    • 3

    总结:仍然是配合filter方法实现去重,没有单独创建方法,临时定义一个HashMap,保持了原列表的顺序,不足之处是有一定内存占用。

  • 相关阅读:
    Linux内核Kernel启动过程
    数据结构之堆(优先级队列)
    简单理解Vue中的数据代理
    MySQL中 LBCC 和 MVCC 的理解,常见问题及示例:
    跨境商城源码有哪些独特的功能和优势
    【译】使用 ChatGPT 和 Azure Cosmos DB 构建智能应用程序
    .NET分布式Orleans - 6 - 事件溯源
    当代工业设计体系里的思维导图
    Mac 重新安装系统
    点云从入门到精通技术详解100篇-基于光谱共焦系统的三维点云数据处理(中)
  • 原文地址:https://blog.csdn.net/sunrj_niu/article/details/128131331