Java中兩個(gè)List之間的比較方法(差集、交集和并集)
實(shí)現(xiàn)比較兩個(gè)List之間的差異,包括獲取兩List的差集,交集,并集(不去重&去重)的API解法和優(yōu)化解法的解決方案。
求差集
/** * 差集(基于API解法) 適用于小數(shù)據(jù)量 * 求List1中有的但是List2中沒有的元素 * 時(shí)間復(fù)雜度 O(list1.size() * list2.size()) */ public static List<String> subList(List<String> list1, List<String> list2) { list1.removeAll(list2); return list1; } /** * 差集(基于常規(guī)解法)優(yōu)化解法1 適用于中等數(shù)據(jù)量 * 求List1中有的但是List2中沒有的元素 * 空間換時(shí)間降低時(shí)間復(fù)雜度 * 時(shí)間復(fù)雜度O(Max(list1.size(),list2.size())) */ public static List<String> subList1(List<String> list1, List<String> list2) { //空間換時(shí)間 降低時(shí)間復(fù)雜度 Map<String, String> tempMap = new HashMap<>(); for(String str:list2){ tempMap.put(str,str); } //LinkedList 頻繁添加刪除 也可以ArrayList容量初始化為List1.size(),防止數(shù)據(jù)量過大時(shí)頻繁擴(kuò)容以及數(shù)組復(fù)制 List<String> resList = new LinkedList<>(); for(String str:list1){ if(!tempMap.containsKey(str)){ resList.add(str); } } return resList; } /** * 差集(基于java8新特性)優(yōu)化解法2 適用于大數(shù)據(jù)量 * 求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解法) 適用于小數(shù)據(jù)量 * 求List1和List2中都有的元素 * 時(shí)間復(fù)雜度 O(list1.size() * list2.size()) */ public static List<String> intersectList(List<String> list1, List<String> list2){ list1.retainAll(list2); return list1; } /** * 交集(基于常規(guī)解法) 優(yōu)化解法1 適用于中等數(shù)據(jù)量 * 求List1和List2中都有的元素 * 時(shí)間復(fù)雜度O(Max(list1.size(),list2.size())) */ public static List<String> intersectList1(List<String> list1, List<String> list2){ //空間換時(shí)間 降低時(shí)間復(fù)雜度 Map<String, String> tempMap = new HashMap<>(); for(String str:list2){ tempMap.put(str,str); } //LinkedList 頻繁添加刪除 也可以ArrayList容量初始化為List1.size(),防止數(shù)據(jù)量過大時(shí)頻繁擴(kuò)容以及數(shù)組復(fù)制 List<String> resList = new LinkedList<>(); for(String str:list1){ if(tempMap.containsKey(str)){ resList.add(str); } } return resList; } /** * 交集(基于java8新特性)優(yōu)化解法2 適用于大數(shù)據(jù)量 * 求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 不考慮去除重復(fù)元素 * 數(shù)組擴(kuò)容 數(shù)組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 去除重復(fù)元素 * 時(shí)間復(fù)雜度主要取決于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新特性 適用于大數(shù)據(jù)量 * 合并list1和list2 去除重復(fù)元素 */ public static List<String> distinctMergeList1(List<String> list1, List<String> list2){ //第一步 先求出list1與list2的差集 list1 = subList2(list1,list2); //第二部 再合并list1和list2 list1.addAll(list2); return list1; }
實(shí)際業(yè)務(wù)場景
根據(jù)客戶需求,業(yè)務(wù)提交審核需要很直觀的看到此次提交的數(shù)據(jù)關(guān)聯(lián)產(chǎn)品的狀態(tài)變更。
第一種情況:新增的渠道授權(quán)關(guān)聯(lián)的產(chǎn)品,所有的授權(quán)產(chǎn)品均為新增;
第二種情況:已審核通過的渠道授權(quán)重新提交授權(quán)審核的,要直觀的標(biāo)記出此次提交審核渠道關(guān)聯(lián)授權(quán)產(chǎn)品新增了那些,刪除了那些,更改了那些等信息;
第三種情況:作廢渠道提交的審核要標(biāo)注出所有的關(guān)聯(lián)授權(quán)產(chǎn)品為刪除狀態(tài)。
授權(quán)關(guān)聯(lián)產(chǎn)品為申請表單中一對多關(guān)聯(lián)表,前端展示根據(jù)數(shù)據(jù)的不同狀態(tài)展示不同的樣式:
- 新增授權(quán)產(chǎn)品顯示為紅色
- 刪除授權(quán)產(chǎn)品顯示為刪除線樣式(中劃線 )
- 更新授權(quán)產(chǎn)品顯示標(biāo)注紅色*號(hào)
建立關(guān)聯(lián)產(chǎn)品Vo
首先模擬建立一個(gè)產(chǎn)品的實(shí)體,此處只簡單列入幾個(gè)屬性,在比較所關(guān)聯(lián)產(chǎn)品信息是否是變更狀態(tài)的時(shí)候根據(jù)實(shí)際業(yè)務(wù)需要需重寫 hashCode 和 equals 方法。
class ProductVo{ private String id; private String name; //其他屬性不在列入 //數(shù)據(jù)狀態(tài)(新增:insert; 更新:update; 刪除:delete) private String status; //get set 省略 //如有必要重寫hashCode equals }
業(yè)務(wù)代碼實(shí)現(xiàn)
業(yè)務(wù)實(shí)現(xiàn)主要通過 空間換時(shí)間 方式降低時(shí)間復(fù)雜度,先把List轉(zhuǎn)為Map,利用map的 get 和 containsKey 方法理想情況下O(1)的時(shí)間復(fù)雜度降低嵌套的兩次List遍歷。
/** * 渠道授權(quán)新提交關(guān)聯(lián)授權(quán)產(chǎn)品 與 歷史已審批授權(quán)信息對比處理標(biāo)注授權(quán)產(chǎn)品的狀態(tài)信息<br/> * 前端可以根據(jù)不同的數(shù)據(jù)狀態(tài)顯示不同的樣式<br/> * 用于審核人員直接看到此次提交審核新增了那些授權(quán),取消了那些授權(quán),更改了那些授權(quán) * @param oldList 原始關(guān)聯(lián)授權(quán)產(chǎn)品列表 * @param newList 提交關(guān)聯(lián)授權(quán)產(chǎn)品列表 * @return */ public List<ProductVo> productStatusHandle(List<ProductVo> oldList,List<ProductVo> newList){ //原始關(guān)聯(lián)授權(quán)產(chǎn)品為空 并且 新關(guān)聯(lián)授權(quán)產(chǎn)品為空(基本不存在此場景) if((oldList == null || oldList.isEmpty()) && (newList == null || newList.isEmpty())){ return Collections.emptyList(); } //原始關(guān)聯(lián)授權(quán)產(chǎn)品為空 則提交關(guān)聯(lián)授權(quán)產(chǎn)品全部為新增 if(oldList == null || oldList.isEmpty()){ return newList.stream().map(vo->{ vo.setStatus("insert"); return vo; }).collect(Collectors.toList()); } //提交關(guān)聯(lián)授權(quán)產(chǎn)品為空 則刪除之前所有的產(chǎn)品授權(quán) if(newList == null || newList.isEmpty()){ return oldList.stream().map(vo->{ vo.setStatus("delete"); return vo; }).collect(Collectors.toList()); } //原始關(guān)聯(lián)授權(quán)產(chǎn)品與此次提交關(guān)聯(lián)授權(quán)產(chǎn)品均不為空 List<ProductVo> resList = new LinkedList<>(); //空間換時(shí)間 降低時(shí)間復(fù)雜度 //說明:list中不會(huì)存在重復(fù)(ID相同)的授權(quán)產(chǎn)品 否則此toMap收集會(huì)拋出異常 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()); //提交關(guān)聯(lián)授權(quán)產(chǎn)品在原始關(guān)聯(lián)授權(quán)產(chǎn)品 if(productVo != null){ if(!vo.equals(productVo)){//重寫hashCode與equals自定義規(guī)則 用于判定是否數(shù)據(jù)更新 vo.setStatus("update"); } }else{//提交審核數(shù)據(jù)不在舊數(shù)據(jù)之列 vo.setStatus("insert"); } resList.add(vo); } //原始關(guān)聯(lián)授權(quán)產(chǎn)品是否存在已取消的情況 for(ProductVo vo:oldList){ if(!newMap.containsKey(vo.getId())){ vo.setStatus("delete"); resList.add(vo); } } return resList; }
總結(jié)
到此這篇關(guān)于Java中兩個(gè)List之間的比較方法的文章就介紹到這了,更多相關(guān)Java中List比較內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 異步編程實(shí)踐_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
異步編程提供了一個(gè)非阻塞的,事件驅(qū)動(dòng)的編程模型。下面通過本文給大家介紹Java 異步編程實(shí)踐,感興趣的的朋友一起看看吧2017-05-05SpringBoot學(xué)習(xí)系列之MyBatis Plus整合封裝的實(shí)例詳解
MyBatis-Plus是一款MyBatis的增強(qiáng)工具(簡稱MP),為簡化開發(fā)、提高效率,這篇文章給大家介紹MyBatis Plus整合封裝的實(shí)例詳解,感興趣的朋友跟隨小編一起看看吧2020-08-08java實(shí)現(xiàn)簡單的加減乘除計(jì)算器
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡單的加減乘除計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09鎖超時(shí)發(fā)現(xiàn)parallelStream并行流線程上下文坑解決
這篇文章主要為大家介紹了鎖超時(shí)發(fā)現(xiàn)parallelStream并行流線程上下文坑解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08Java練習(xí)之潛艇小游戲的實(shí)現(xiàn)
這篇文章主要和大家分享一個(gè)Java小練習(xí)——利用Java編寫一個(gè)潛艇小游戲,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-03-03使用javaMail實(shí)現(xiàn)發(fā)送郵件
這篇文章主要為大家詳細(xì)介紹了使用javaMail實(shí)現(xiàn)發(fā)送郵件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08