Java中两个List之间的比较方法(差集、交集和并集)
作者:程序猿不源 发布时间:2023-03-06 06:34:42
标签:java,list,比较
实现比较两个List之间的差异,包括获取两List的差集,交集,并集(不去重&去重)的API解法和优化解法的解决方案。
求差集
/**
* 差集(基于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的 get 和 containsKey 方法理想情况下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;
}
来源:https://blog.csdn.net/m0_66782750/article/details/123980925


猜你喜欢
- Apache Dubbo是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡
- 使用后台返回验证码图片,验证码存到session中后端实现校验,前端只展示验证码图片。本篇用SpringBoot Thymeleaf实现验证
- 一、bean实例化——构造方法(常用)bean本质上就是对象,创建bean使用构造方法完成BookD
- 本文实例讲述了C#使用iTextSharp从PDF文档获取内容的方法。分享给大家供大家参考。具体实现方法如下:using System;us
- Android PopWindow 设置背景亮度的实例设置背景 /** * 设置添加屏幕的背景透明度 * @param bgAl
- 这是Hadoop学习全程记录第1篇,在这篇里我将介绍一下如何在Linux下安装Hadoop1.x。先说明一下我的开发环境:虚拟机:VMwar
- C#中List可谓是使用最广泛的一种数据类型了,使用他来规范数据时,往往会涉及到对数据的处理操作,相关处理数据方法也非常丰富,本文将简单介绍
- 图库在播放幻灯片时,按power键灭屏,然后再亮屏,会发现幻灯片继续在播放,没有显示keyguard。如何在亮屏后显示解锁界面。 修改方法是
- FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于Internet上的控制文件
- 本文实例为大家分享了PhotoView实现图片双击放大单击退出的具体代码,供大家参考,具体内容如下实现思路1.复制PhotoView&nbs
- 本文实例讲述了C#实现文件压缩与解压的方法。分享给大家供大家参考,具体如下:在企业开发过程中经常会遇到文件的压缩与解压,虽然网上很多流行的压
- 一、No serializer found for class org.hibernate.proxy.pojo.bytebuddy.Byt
- 1.概述最近一直都在带实习生做项目,发现自己好久没有写博客了,这几天更新会比较频繁,今天玩QQ的时候发现QQ主页菜单滑动效果早就变了,实在忍
- 确保这个修改是正确的(否则将会出现乱码)创建i18n文件夹(就是国际化的意思),然后在此文件加下创login.properties logi
- 样式效果 还是先来看效果: 这是一个仿雷达扫描的效果,是之前在做地图sdk接入时就想实现的效果,但之前由于赶着毕业设
- 本文实例为大家分享了java实现多个文件压缩的具体代码,供大家参考,具体内容如下需要用到的ant.jarpackage util;impor
- 一.MyBatis简介1)MyBatis 是一款优秀的持久层框架2)MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结
- 本篇文章是SpringBoot最入门的介绍。我们不借助任何额外的工具,从无到有创建一个Spring Boot的web项目,并运行这个项目。项
- 现在的智能手机不敢说百分百的都是触摸屏,也应该是百分之九九以上为触摸屏了,触摸屏为我们操作无键盘、无鼠标的手机系统带来了很多的便利。当用户触
- 前言这几天学习谷粒商城又再次的回顾了一次SpringCache,之前在学习谷粒学院的时候其实已经学习了一次了!!!这里就对自己学过来的内容进