Java中两个List之间的比较方法(差集、交集和并集)

网友投稿 732 2022-07-23


目录求差集求交集求并集(不去重)求并集(去重)实际业务场景建立关联产品Vo业务代码实现总结

实现比较两个List之间的差异,包括获取两List的差集,交集,并集(不去重&去重)的API解法和优化解法的解决方案。

求差集

/**

* 差集(基于API解法) 适用于小数据量

* 求List1中有的但是List2中没有的元素

* 时间复杂度 O(list1.size() * list2.size())

*/

public static List subList(List list1, List list2) {

list1.removeAll(list2);

return list1;

}

/**

* 差集(基于常规解法)优化解法1 适用于中等数据量

* 求List1中有的但是List2中没有的元素

* 空间换时间降低时间复杂度

* 时间复杂度O(Max(list1.size(),list2.size()))

*/

public static List subList1(List list1, List list2) {

//空间换时间 降低时间复杂度

Map tempMap = new HashMap<>();

for(String str:list2){

tempMap.put(str,str);

}

//LinkedList 频繁添加删除 也可以ArrayList容量初始化为List1.size(),防止数据量过大时频繁扩容以及数组复制

List resList = new LinkedList<>();

for(String str:list1){

if(!tempMap.containsKey(str)){

resList.add(str);

}

}

return resList;

}

/**

* 差集(基于java8新特性)优化解法2 适用于大数据量

* 求List1中有的但是List2中没有的元素

*/

public static List subList2(List list1, List list2) {

Map 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 intersectList(List list1, List list2){

list1.retainAll(list2);

return list1;

}

/**

* 交集(基于常规解法) 优化解法1 适用于中等数据量

* 求List1和List2中都有的元素

* 时间复杂度O(Max(list1.size(),list2.size()))

*/

public static List intersectList1(List list1, List list2){

//空间换时间 降低时间复杂度

Map tempMap = new HashMap<>();

for(String str:list2){

tempMap.put(str,str);

}

//LinkedList 频繁添加删除 也可以ArrayList容量初始化为List1.size(),防止数据量过大时频繁扩容以及数组复制

List resList = new LinkedList<>();

for(String str:list1){

if(tempMap.containsKey(str)){

resList.add(str);

}

}

return resList;

}

/**

* 交集(基于java8新特性)优化解法2 适用于大数据量

* 求List1和List2中都有的元素

*/

public static List intersectList2(List list1, List list2){

Map 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 mergeList(List list1, List list2){

list1.addAll(list2);

return list1;

}

求并集(去重)

/**

* 并集(去重) 基于API解法

* 合并list1和list2 去除重复元素

* 时间复杂度主要取决于removeAll 取差集 O(list1.size() * list2.size())

*/

public static List distinctMergeList(List list1, List list2){

//第一步 先求出list1与list2的差集

list1.removeAll(list2);

//第二部 再合并list1和list2

list1.addAll(list2);

return list1;

}

/**

* 并集(去重) 基于Java8新特性 适用于大数据量

* 合并list1和list2 去除重复元素

*/

public static List distinctMergeList1(List list1, List 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的 get 和 containsKey 方法理想情况下O(1)的时间复杂度降低嵌套的两次List遍历。

/**

* 渠道授权新提交关联授权产品 与 历史已审批授权信息对比处理标注授权产品的状态信息

* 前端可以根据不同的数据状态显示不同的样式

* 用于审核人员直接看到此次提交审核新增了那些授权,取消了那些授权,更改了那些授权

* @param oldList 原始关联授权产品列表

* @param newList 提交关联授权产品列表

* @return

*/

public List productStatusHandle(List oldList,List 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 resList = new LinkedList<>();

//空间换时间 降低时间复杂度

//说明:list中不会存在重复(ID相同)的授权产品 否则此toMap收集会抛出异常

Map oldMap = oldList.stream().collect(Collectors.toMap(ProductVo::getId, Function.identity()));

Map 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())){

http:// vo.setStatus("delete");

resList.add(vo);

}

}

return resList;

}

总结


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java中Spring扩展点详解
下一篇:JAVA连接到SQLserver的步骤方法以及遇到的问题
相关文章

 发表评论

暂时没有评论,来抢沙发吧~