相关文章推荐
粗眉毛的啄木鸟  ·  [Solved] Invalid call ...·  1 年前    · 
高大的热带鱼  ·  springboot ...·  1 年前    · 

本文实现了比较两个List之间的差异,包括获取两List的差集,交集,并集(不去重)和 并集(去重)的API解法和优化解法的解决方案,并根据实际业务场景实现业务需求。

本文中在比较两个List之间的差异时,为了代码简洁未对入参进行空值判断,根据实际需求可以对入参进行非空判断以及相应的业务处理。

* 差集(基于API解法) 适用于小数据量 * 求List1中有的但是List2中没有的元素 * 时间复杂度 O(list1.size() * list2.size()) public static List < String > subList ( List < String > list1 , List < String > list2 ) { list1 . removeAll ( list2 ) ; return list1 ; * 差集(基于常规解法)优化解法1 适用于中等数据量 * 求List1中有的但是List2中没有的元素 * 空间换时间降低时间复杂度 * 时间复杂度O(Max(list1.size(),list2.size())) public static List < String > subList1 ( List < String > list1 , List < String > list2 ) { //空间换时间 降低时间复杂度 Map < String , String > tempMap = new HashMap < > ( ) ; for ( String str : list2 ) { tempMap . put ( str , str ) ; //LinkedList 频繁添加删除 也可以ArrayList容量初始化为List1.size(),防止数据量过大时频繁扩容以及数组复制 List < String > resList = new LinkedList < > ( ) ; for ( String str : list1 ) { if ( ! tempMap . containsKey ( str ) ) { resList . add ( str ) ; return resList ; * 差集(基于java8新特性)优化解法2 适用于大数据量 * 求List1中有的但是List2中没有的元素 public static List < String > subList2 ( List < String > list1 , List < String > list2 ) { Map < String , String > tempMap = list2 . parallelStream ( ) . collect ( Collectors . toMap ( Function . identity ( ) , Function . identity ( ) , ( oldData , newData ) - > newData ) ) ; return list1 . parallelStream ( ) . filter ( str - > { return ! tempMap . containsKey ( str ) ; } ) . collect ( Collectors . toList ( ) ) ; * 交集(基于API解法) 适用于小数据量 * 求List1和List2中都有的元素 * 时间复杂度 O(list1.size() * list2.size()) public static List < String > intersectList ( List < String > list1 , List < String > list2 ) { list1 . retainAll ( list2 ) ; return list1 ; * 交集(基于常规解法) 优化解法1 适用于中等数据量 * 求List1和List2中都有的元素 * 时间复杂度O(Max(list1.size(),list2.size())) public static List < String > intersectList1 ( List < String > list1 , List < String > list2 ) { //空间换时间 降低时间复杂度 Map < String , String > tempMap = new HashMap < > ( ) ; for ( String str : list2 ) { tempMap . put ( str , str ) ; //LinkedList 频繁添加删除 也可以ArrayList容量初始化为List1.size(),防止数据量过大时频繁扩容以及数组复制 List < String > resList = new LinkedList < > ( ) ; for ( String str : list1 ) { if ( tempMap . containsKey ( str ) ) { resList . add ( str ) ; return resList ; * 交集(基于java8新特性)优化解法2 适用于大数据量 * 求List1和List2中都有的元素 public static List < String > intersectList2 ( List < String > list1 , List < String > list2 ) { Map < String , String > tempMap = list2 . parallelStream ( ) . collect ( Collectors . toMap ( Function . identity ( ) , Function . identity ( ) , ( oldData , newData ) - > newData ) ) ; return list1 . parallelStream ( ) . filter ( str - > { return tempMap . containsKey ( str ) ; } ) . collect ( Collectors . toList ( ) ) ;

求并集(不去重)

* 并集(不去重) * 合并list1和list2 不考虑去除重复元素 * 数组扩容 数组copy * @param list1 * @param list2 * @return public static List < String > mergeList ( List < String > list1 , List < String > list2 ) { list1 . addAll ( list2 ) ; return list1 ;

求并集(除去重复)

* 并集(去重) 基于API解法 * 合并list1和list2 去除重复元素 * 时间复杂度主要取决于removeAll 取差集 O(list1.size() * list2.size()) public static List < String > distinctMergeList ( List < String > list1 , List < String > list2 ) { //第一步 先求出list1与list2的差集 list1 . removeAll ( list2 ) ; //第二部 再合并list1和list2 list1 . addAll ( list2 ) ; return list1 ; * 并集(去重) 基于Java8新特性 适用于大数据量 * 合并list1和list2 去除重复元素 public static List < String > distinctMergeList1 ( List < String > list1 , List < String > list2 ) { //第一步 先求出list1与list2的差集 list1 = subList2 ( list1 , list2 ) ; //第二部 再合并list1和list2 list1 . addAll ( list2 ) ; return list1 ;

实际业务场景

根据客户需求,业务提交审核需要很直观的看到此次提交的数据关联产品的状态变更。
第一种情况:新增的渠道授权关联的产品,所有的授权产品均为新增;
第二种情况:已审核通过的渠道授权重新提交授权审核的,要直观的标记出此次提交审核渠道关联授权产品新增了那些,删除了那些,更改了那些等信息;
第三种情况:作废渠道提交的审核要标注出所有的关联授权产品为删除状态。

授权关联产品为申请表单中一对多关联表,前端展示根据数据的不同状态展示不同的样式:
新增授权产品显示为红色
删除授权产品显示为删除线样式( 中划线 )
更新授权产品显示标注红色*号

建立关联产品Vo

首先模拟建立一个产品的实体,此处只简单列入几个属性,在比较所关联产品信息是否是变更状态的时候根据实际业务需要需重写 hashCode 和 equals 方法。

class ProductVo{
    private String id;
    private String name;
    //其他属性不在列入
    //数据状态(新增:insert; 更新:update; 删除:delete)
    private String status;
    //get set 省略
    //如有必要重写hashCode equals

业务代码实现

业务实现主要通过 空间换时间 方式降低时间复杂度,先把List转为Map,利用map的 getcontainsKey 方法理想情况下O(1)的时间复杂度降低嵌套的两次List遍历。

* 渠道授权新提交关联授权产品 与 历史已审批授权信息对比处理标注授权产品的状态信息<br/> * 前端可以根据不同的数据状态显示不同的样式<br/> * 用于审核人员直接看到此次提交审核新增了那些授权,取消了那些授权,更改了那些授权 * @param oldList 原始关联授权产品列表 * @param newList 提交关联授权产品列表 * @return public List<ProductVo> productStatusHandle(List<ProductVo> oldList,List<ProductVo> newList){ //原始关联授权产品为空 并且 新关联授权产品为空(基本不存在此场景) if((oldList == null || oldList.isEmpty()) && (newList == null || newList.isEmpty())){ return Collections.emptyList(); //原始关联授权产品为空 则提交关联授权产品全部为新增 if(oldList == null || oldList.isEmpty()){ return newList.stream().map(vo->{ vo.setStatus("insert"); return vo; }).collect(Collectors.toList()); //提交关联授权产品为空 则删除之前所有的产品授权 if(newList == null || newList.isEmpty()){ return oldList.stream().map(vo->{ vo.setStatus("delete"); return vo; }).collect(Collectors.toList()); //原始关联授权产品与此次提交关联授权产品均不为空 List<ProductVo> resList = new LinkedList<>(); //空间换时间 降低时间复杂度 //说明:list中不会存在重复(ID相同)的授权产品 否则此toMap收集会抛出异常 Map<String, ProductVo> oldMap = oldList.stream().collect(Collectors.toMap(ProductVo::getId, Function.identity())); Map<String, ProductVo> newMap = newList.stream().collect(Collectors.toMap(ProductVo::getId, Function.identity())); for(ProductVo vo:newList){ ProductVo productVo = oldMap.get(vo.getId()); //提交关联授权产品在原始关联授权产品 if(productVo != null){ if(!vo.equals(productVo)){//重写hashCode与equals自定义规则 用于判定是否数据更新 vo.setStatus("update"); }else{//提交审核数据不在旧数据之列 vo.setStatus("insert"); resList.add(vo); //原始关联授权产品是否存在已取消的情况 for(ProductVo vo:oldList){ if(!newMap.containsKey(vo.getId())){ vo.setStatus("delete"); resList.add(vo); return resList;
转自同名博文,未知真正出处,望作者见谅 如题:有List list1和List list2,两个集合各有上万个元素,怎样取出两个集合中不同的元素? 方法1:遍历两个集合: package com.czp.test; import java.util.ArrayList; import java.util.List; public class TestList { publi
Java编程经验---比较两个List对象差异问题引入解决问题简化模型 如何比较两个List对象的差异,这个问题来源于我最近正在开发的新系统中的一个细节。大致情况就是,从数据库中的一个视图A向另一个数据库的一张B表进行数据迁移。A的数据会随时更新,为了保证表B也可以及时获取数据,需要采用定时任务,不断同步数据。 每N分钟视图A表B 视图A中的数据在导入表B时,可能有数据已经在表B中,重复的导入浪费性能且可能发生潜在错误。那么就需要分析数据的差异后进行导入。先设一个前提,视图A与表B的结构相似,Pr
1. 判断两个List的长度是否相等,如果长度不同,则认为它们不相等。 2. 判断两个List元素是否相等,可以通过比较每个元素来实现。可以使用List自带的equals()方法进行比较,也可以使用逐个遍历元素。 3. 如果两个List都包含其他对象,则需要考虑这些元素比较方式。可以使用对象自带的equals()方法进行比较,也可以自定义比较方式。 例如,比较ListA和ListB是否相等可以使用以下代码: public boolean isEqual(List listA, List listB) { if (listA.size() != listB.size()) { return false; for (int i = 0; i < listA.size(); i++) { if (!listA.get(i).equals(listB.get(i))) { return false; return true; 这个方法首先判断两个List的长度是否相等,如果不相等,则返回false。然后在一个for循环中逐个比较两个List元素是否相等,如果有元素不相等,则返回false。如果所有元素都相等,则返回true。 另外,如果两个List包含的元素对象是自定义的类对象,则可以在这个类的定义中重写equals()方法和hashCode()方法来实现元素比较。这样,在比较列表时就可以直接使用equals()方法来比较元素,而不需要再自定义比较方式。