转自同名博文,未知真正出处,望作者见谅

如题:有List<String> list1和List<String> list2,两个集合各有上万个元素,怎样取出两个集合中不同的元素?

方法1:遍历两个集合:

package com.czp.test;import java.util.ArrayList;
import java.util.List;public class TestList {public static void main(String[] args) {List<String> list1 = new ArrayList<String>();List<String> list2 = new ArrayList<String>();for (int i = 0; i < 10000; i++) {list1.add("test"+i);list2.add("test"+i*2);}getDiffrent(list1,list2);//输出:total times 2566454675
    }/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent(List<String> list1, List<String> list2) {long st = System.nanoTime();List<String> diff = new ArrayList<String>();for(String str:list1){if(!list2.contains(str)){diff.add(str);}}System.out.println("total times "+(System.nanoTime()-st));return diff;}
}

千万不要采用这种方法,总共要循环的次数是两个List的size相乘的积,从输出看耗时也是比较长的,那么我们有没有其他的方法呢?当然有.

方法2:采用List提供的retainAll()方法:

package com.czp.test;import java.util.ArrayList;
import java.util.List;public class TestList {public static void main(String[] args) {List<String> list1 = new ArrayList<String>();List<String> list2 = new ArrayList<String>();for (int i = 0; i < 10000; i++) {list1.add("test"+i);list2.add("test"+i*2);}getDiffrent(list1,list2);//输出:total times 2566454675
        getDiffrent2(list1,list2);//输出:getDiffrent2 total times 2787800964
    }/*** 获取连个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent2(List<String> list1, List<String> list2) {long st = System.nanoTime();list1.retainAll(list2);System.out.println("getDiffrent2 total times "+(System.nanoTime()-st));return list1;}/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent(List<String> list1, List<String> list2) {long st = System.nanoTime();List<String> diff = new ArrayList<String>();for(String str:list1){if(!list2.contains(str)){diff.add(str);}}System.out.println("getDiffrent total times "+(System.nanoTime()-st));return diff;}
}
很遗憾,这种方式虽然只要几行代码就搞定,但是这个却更耗时,查看retainAll()的源码:public boolean retainAll(Collection<?> c) {boolean modified = false;Iterator<E> e = iterator();while (e.hasNext()) {if (!c.contains(e.next())) {e.remove();modified = true;}}return modified;}

无需解释这个耗时是必然的,那么我们还有没有更好的办法呢?仔细分析以上两个方法中我都做了mXn次循环,其实完全没有必要循环这么多次,我们的需求是找出两个List中的不同元素,那么我可以这样考虑:用一个map存放lsit的所有元素,其中的key为lsit1的各个元素,value为该元素出现的次数,接着把list2的所有元素也放到map里,如果已经存在则value加1,最后我们只要取出map里value为1的元素即可,这样我们只需循环m+n次,大大减少了循环的次数。
package com.czp.test;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class TestList {public static void main(String[] args) {List<String> list1 = new ArrayList<String>();List<String> list2 = new ArrayList<String>();for (int i = 0; i < 10000; i++) {list1.add("test"+i);list2.add("test"+i*2);}getDiffrent(list1,list2);//输出:total times 2566454675
        getDiffrent2(list1,list2);//输出:getDiffrent2 total times 2787800964
        getDiffrent3(list1,list2);//输出:getDiffrent3 total times 61763995
    }/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent3(List<String> list1, List<String> list2) {long st = System.nanoTime();Map<String,Integer> map = new HashMap<String,Integer>(list1.size()+list2.size());List<String> diff = new ArrayList<String>();for (String string : list1) {map.put(string, 1);}for (String string : list2) {Integer cc = map.get(string);if(cc!=null){map.put(string, ++cc);continue;}map.put(string, 1);}for(Map.Entry<String, Integer> entry:map.entrySet()){if(entry.getValue()==1){diff.add(entry.getKey());}}System.out.println("getDiffrent3 total times "+(System.nanoTime()-st));return list1;}/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent2(List<String> list1, List<String> list2) {long st = System.nanoTime();list1.retainAll(list2);System.out.println("getDiffrent2 total times "+(System.nanoTime()-st));return list1;}/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent(List<String> list1, List<String> list2) {long st = System.nanoTime();List<String> diff = new ArrayList<String>();for(String str:list1){if(!list2.contains(str)){diff.add(str);}}System.out.println("getDiffrent total times "+(System.nanoTime()-st));return diff;}
}

显然,这种方法大大减少耗时,是方法1的1/4,是方法2的1/40,这个性能的提升时相当可观的,但是,这不是最佳的解决方法,观察方法3我们只是随机取了一个list作为首次添加的标准,这样一旦我们的list2比list1的size大,则我们第二次put时的if判断也会耗时,做如下改进:
package com.czp.test;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class TestList {public static void main(String[] args) {List<String> list1 = new ArrayList<String>();List<String> list2 = new ArrayList<String>();for (int i = 0; i < 10000; i++) {list1.add("test"+i);list2.add("test"+i*2);}getDiffrent(list1,list2);getDiffrent2(list1,list2);getDiffrent3(list1,list2);getDiffrent4(list1,list2);
//        getDiffrent total times 2789492240
//        getDiffrent2 total times 3324502695
//        getDiffrent3 total times 24710682
//        getDiffrent4 total times 15627685
    }/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent4(List<String> list1, List<String> list2) {long st = System.nanoTime();Map<String,Integer> map = new HashMap<String,Integer>(list1.size()+list2.size());List<String> diff = new ArrayList<String>();List<String> maxList = list1;List<String> minList = list2;if(list2.size()>list1.size()){maxList = list2;minList = list1;}for (String string : maxList) {map.put(string, 1);}for (String string : minList) {Integer cc = map.get(string);if(cc!=null){map.put(string, ++cc);continue;}map.put(string, 1);}for(Map.Entry<String, Integer> entry:map.entrySet()){if(entry.getValue()==1){diff.add(entry.getKey());}}System.out.println("getDiffrent4 total times "+(System.nanoTime()-st));return diff;}/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent3(List<String> list1, List<String> list2) {long st = System.nanoTime();Map<String,Integer> map = new HashMap<String,Integer>(list1.size()+list2.size());List<String> diff = new ArrayList<String>();for (String string : list1) {map.put(string, 1);}for (String string : list2) {Integer cc = map.get(string);if(cc!=null){map.put(string, ++cc);continue;}map.put(string, 1);}for(Map.Entry<String, Integer> entry:map.entrySet()){if(entry.getValue()==1){diff.add(entry.getKey());}}System.out.println("getDiffrent3 total times "+(System.nanoTime()-st));return diff;}/*** 获取连个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent2(List<String> list1, List<String> list2) {long st = System.nanoTime();list1.retainAll(list2);System.out.println("getDiffrent2 total times "+(System.nanoTime()-st));return list1;}/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent(List<String> list1, List<String> list2) {long st = System.nanoTime();List<String> diff = new ArrayList<String>();for(String str:list1){if(!list2.contains(str)){diff.add(str);}}System.out.println("getDiffrent total times "+(System.nanoTime()-st));return diff;}
}

这里对连个list的大小进行了判断,小的在最后添加,这样会减少循环里的判断,性能又有了一定的提升,正如一位朋友所说,编程是无止境的,只要你认真去思考了,总会找到更好的方法!

非常感谢binglian的指正,针对List有重复元素的问题,做以下修正,首先明确一点,两个List不管有多少个重复,只要重复的元素在两个List都能找到,则不应该包含在返回值里面,所以在做第二次循环时,这样判断:如果当前元素在map中找不到,则肯定需要添加到返回值中,如果能找到则value++,遍历完之后diff里面已经包含了只在list2里而没在list2里的元素,剩下的工作就是找到list1里有list2里没有的元素,遍历map取value为1的即可:

package com.czp.test;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class TestList {public static void main(String[] args) {List<String> list1 = new ArrayList<String>();List<String> list2 = new ArrayList<String>();for (int i = 0; i < 10000; i++) {list1.add("test"+i);list2.add("test"+i*2);}getDiffrent(list1,list2);getDiffrent3(list1,list2);getDiffrent5(list1,list2);getDiffrent4(list1,list2);getDiffrent2(list1,list2);//        getDiffrent3 total times 32271699
//        getDiffrent5 total times 12239545
//        getDiffrent4 total times 16786491
//        getDiffrent2 total times 2438731459
        }/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent5(List<String> list1, List<String> list2) {long st = System.nanoTime();List<String> diff = new ArrayList<String>();List<String> maxList = list1;List<String> minList = list2;if(list2.size()>list1.size()){maxList = list2;minList = list1;}Map<String,Integer> map = new HashMap<String,Integer>(maxList.size());for (String string : maxList) {map.put(string, 1);}for (String string : minList) {if(map.get(string)!=null){map.put(string, 2);continue;}diff.add(string);}for(Map.Entry<String, Integer> entry:map.entrySet()){if(entry.getValue()==1){diff.add(entry.getKey());}}System.out.println("getDiffrent5 total times "+(System.nanoTime()-st));return diff;}/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent4(List<String> list1, List<String> list2) {long st = System.nanoTime();Map<String,Integer> map = new HashMap<String,Integer>(list1.size()+list2.size());List<String> diff = new ArrayList<String>();List<String> maxList = list1;List<String> minList = list2;if(list2.size()>list1.size()){maxList = list2;minList = list1;}for (String string : maxList) {map.put(string, 1);}for (String string : minList) {Integer cc = map.get(string);if(cc!=null){map.put(string, ++cc);continue;}map.put(string, 1);}for(Map.Entry<String, Integer> entry:map.entrySet()){if(entry.getValue()==1){diff.add(entry.getKey());}}System.out.println("getDiffrent4 total times "+(System.nanoTime()-st));return diff;}/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent3(List<String> list1, List<String> list2) {long st = System.nanoTime();Map<String,Integer> map = new HashMap<String,Integer>(list1.size()+list2.size());List<String> diff = new ArrayList<String>();for (String string : list1) {map.put(string, 1);}for (String string : list2) {Integer cc = map.get(string);if(cc!=null){map.put(string, ++cc);continue;}map.put(string, 1);}for(Map.Entry<String, Integer> entry:map.entrySet()){if(entry.getValue()==1){diff.add(entry.getKey());}}System.out.println("getDiffrent3 total times "+(System.nanoTime()-st));return diff;}/*** 获取连个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent2(List<String> list1, List<String> list2) {long st = System.nanoTime();list1.retainAll(list2);System.out.println("getDiffrent2 total times "+(System.nanoTime()-st));return list1;}/*** 获取两个List的不同元素* @param list1* @param list2* @return*/private static List<String> getDiffrent(List<String> list1, List<String> list2) {long st = System.nanoTime();List<String> diff = new ArrayList<String>();for(String str:list1){if(!list2.contains(str)){diff.add(str);}}System.out.println("getDiffrent total times "+(System.nanoTime()-st));return diff;}
}


转载于:https://www.cnblogs.com/feifeicui/p/9958389.html

高效的找出两个List中的不同元素相关推荐

  1. 汇编语言(十五)之找出两个数组中的相同元素

    找出两个数组中的相同元素,并且输出 程序运行: 代码: datas segmentA dw -1,-2, 3, 4, 5, 6, 7, 8, 9, 10,-11, 12, 13, 14, 15ACou ...

  2. js 快速找出两个数组中的不同元素或对象

    js 快速找出两个数组中的不同元素 var arr1 = [0,1,2,3,4,5]; var arr2 = [0,4,6,1,3,9]; function getArrDifference(arr1 ...

  3. JS案例——找出两个数组中的不同元素或对象、数组去重

    一.找出两个数组中的不同元素或对象 1. 数据 var arr1 = ["张瑞淑", "徐海涛", "谢岗岗", "薛鹏" ...

  4. 找出两列表的共有元素python_python 找出两个dataframe中不同的元素

    pandas从Excel中读取数据,数据格式为dataframe格式 用for循环对进行两个列的数据比较想找出不同的元素时,发现数据是一样的,但是比较结果却是相同和不同的都存在(总之就是不是我以为的效 ...

  5. python 找出两个dataframe中不同的元素

    pandas从Excel中读取数据,数据格式为dataframe格式 用for循环对进行两个列的数据比较想找出不同的元素时,发现数据是一样的,但是比较结果却是相同和不同的都存在(总之就是不是我以为的效 ...

  6. js找出两个数组中不同的元素

    function getNewArr(a,b){const arr = [...a,...b];const newArr = arr.filter(item => {return !(a.inc ...

  7. 找出两个字符串中最大子字符串,如abractyeyt,dgdsaeactyey的最大子串为actyet

    // 最大子字符串.cpp : 定义控制台应用程序的入口点. // //找出两个字符串中最大子字符串,如"abractyeyt","dgdsaeactyey"的 ...

  8. 找出两个字符串中最长的相同子字符串

    //找出两个字符串中最长的相同子字符串public class Stringdemo {public static void main(String[] args) {String str1 = ne ...

  9. java基础—找出两个字符串中最大的子串

    // 找一个字符串的最大子串public static void main(String[] args) {String s1 = "qwerabcdtyuiop";String ...

最新文章

  1. Linux中TFTP使用详解
  2. windows 下常用命令行
  3. 给定一个函数做其最佳平方逼近c语言,求函数f(x)在指定区间上对于Φ=span{1,x}最佳平方逼近多项式: (1),[1,3]; (2...
  4. Kali忘记登录密码——修改root密码
  5. mysql查询新建查询报错_mysql开启慢查询报错:
  6. 38 MM配置-采购-采购订单-采购订单审批-定义采购订单审批过程
  7. 计算机网络管理2018版,2018~2019学年度第二学期“计算机网络管理”专业技能竞赛火热进行中...
  8. SharePoint 站点出现Http 503 错误
  9. 这群程序员工作日竟然不用上班?
  10. C#操作XML的完整例子——XmlDocument篇(转载,仅做学习之用)
  11. Restorator 2007 Build 1709 韦斯特*金 汉化版
  12. QQ分享功能实现-Android
  13. win10熄屏时间不对_win10系统屏幕熄屏时间的设置方法
  14. 自学Java day12 使用jvav实现链表 从jvav到架构师
  15. 产品岗常见名词公式及分析方法
  16. 【记录】用Python webdriver图书馆抢座自动预约的正确姿势
  17. 指针真的是个小机灵--将字符串中的n个字符左移,串中的前n个字符移到最后
  18. jira 史诗 故事 任务_史诗般的数据提取任务
  19. 音乐播放时跳动的音符
  20. 数据结构与算法之2-3-4树

热门文章

  1. php 时间倒计时代码 个人写法 有好的想法的欢迎贴出来分享
  2. aspx 与 ashx cs
  3. 【推荐】Redhat 5配置YUM服务器【利用DVD盘做yum源】
  4. matlab拟合曲线后求导,高手留步:MATLAB五阶拟合函数,求导后离散化,输出结果是星号...
  5. shiro放行_Shiro在Spring Boot中的实践
  6. hot编码 字符one_使用字符级RNN生成名字
  7. hql中获取前一天的数据_oracle实现动态查询前一天早八点到当天早八点的数据功能示例...
  8. python处理心电图_ECG心电信号处理:使用WFDB对MIT-BIH数据集进行读取(Python)
  9. fj怎么样_一朝中毒普拉多,万能解药FJ酷路泽
  10. 浙江大学计算机考研大纲,2018年浙江大学研究生入学考试《计算机学科专业基础》(878)考试大纲...