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

方法1:遍历两个集合

  1. public static void main(String[] args) {
  2. List<String> list1 = new ArrayList<String>();
  3. List<String> list2 = new ArrayList<String>();
  4.  
  5. for(int i = 0; i < 10000; i++){
  6. list1.add("test" + i);
  7. list2.add("test" + i*2);
  8. }
  9. getDifferent(list1, list2);
  10. getDiffrent2(list1, list2);
  11. getDiffrent3(list1, list2);
  12. getDiffrent4(list1, list2);
  13. }
  14.  
  15. private static List<String> getDifferent(List<String> list1, List<String> list2){
  16. long startTime = System.currentTimeMillis();
  17. List<String> diff = new ArrayList<String>();
  18. for(String str : list1){
  19. if(!list2.contains(str)){
  20. diff.add(str);
  21. }
  22. }
  23. System.out.println("Total Time: " + (System.currentTimeMillis() - startTime));
  24. return diff;
  25. }
  1. 千万不要采用这种方法,总共要循环的次数是两个Listsize相乘的积,从输出看耗时也是比较长的,那么我们有没有其他的方法呢?当然有.
  2.  
  3. 方法2:采用List提供的retainAll()方法:
  1. public static void main(String[] args) {
  2. List<String> list1 = new ArrayList<String>();
  3. List<String> list2 = new ArrayList<String>();
  4.  
  5. for (int i = 0; i < 10000; i++) {
  6. list1.add("test" + i);
  7. list2.add("test" + i * 2);
  8. }
  9. getDifferent(list1, list2);
  10. }
  11.  
  12. private static List<String> getDiffrent2(List<String> list1, List<String> list2) {
  13. long startTime = System.currentTimeMillis();
  14. list1.retainAll(list2);
  15. System.out.println("Total Time: " + (System.currentTimeMillis() - startTime));
  16. return list1;
  17. }

很遗憾,这种方式虽然只要几行代码就搞定,但是这个却更耗时,查看retainAll()的源码:

  1. public boolean retainAll(Collection<?> c) {
  2. boolean modified = false;
  3. Iterator<E> e = iterator();
  4. while (e.hasNext()) {
  5. if (!c.contains(e.next())) {
  6. e.remove();
  7. modified = true;
  8. }
  9. }
  10. return modified;
  11. }

无需解释这个耗时是必然的,那么我们还有没有更好的办法呢?仔细分析以上两个方法中我都做了mXn次循环,其实完全没有必要循环这么多次,我们的需求是找出两个List中的不同元素,那么我可以这样考虑:用一个map存放lsit的所有元素,其中的key为lsit1的各个元素,value为该元素出现的次数,接着把list2的所有元素也放到map里,如果已经存在则value加1,最后我们只要取出map里value为1的元素即可,这样我们只需循环m+n次,大大减少了循环的次数。

  1. private static List<String> getDiffrent3(List<String> list1, List<String> list2) {
  2. long startTime = System.currentTimeMillis();
  3. Map<String, Integer> map = new HashMap<String, Integer>(list1.size() + list2.size());
  4. List<String> diff = new ArrayList<String>();
  5. for (String string : list1) {
  6. map.put(string, 1);
  7. }
  8. for (String string : list2) {
  9. Integer cc = map.get(string);
  10. if (cc != null) {
  11. map.put(string, ++cc);
  12. continue;
  13. }
  14. map.put(string, 1);
  15. }
  16. for (Map.Entry<String, Integer> entry : map.entrySet()) {
  17. if (entry.getValue() == 1) {
  18. diff.add(entry.getKey());
  19. }
  20. }
  21. System.out.println("Total Time: " + (System.currentTimeMillis() - startTime));
  22. return list1;
  23. }
  1. 显然,这种方法大大减少耗时,是方法11/4,是方法21/40,这个性能的提升时相当可观的,但是,这不是最佳的解决方法,观察方法3我们只是随机取了一个list作为首次添加的标准,这样一旦我们的list2list1size大,则我们第二次put时的if判断也会耗时,做如下改进:
  1. private static List<String> getDiffrent4(List<String> list1, List<String> list2) {
  2. long st = System.nanoTime();
  3. Map<String,Integer> map = new HashMap<String,Integer>(list1.size()+list2.size());
  4. List<String> diff = new ArrayList<String>();
  5. List<String> maxList = list1;
  6. List<String> minList = list2;
  7. if(list2.size()>list1.size())
  8. {
  9. maxList = list2;
  10. minList = list1;
  11. }
  12. for (String string : maxList) {
  13. map.put(string, 1);
  14. }
  15. for (String string : minList) {
  16. Integer cc = map.get(string);
  17. if(cc!=null)
  18. {
  19. map.put(string, ++cc);
  20. continue;
  21. }
  22. map.put(string, 1);
  23. }
  24. for(Map.Entry<String, Integer> entry:map.entrySet())
  25. {
  26. if(entry.getValue()==1)
  27. {
  28. diff.add(entry.getKey());
  29. }
  30. }
  31. System.out.println("getDiffrent4 total times "+(System.nanoTime()-st));
  32. return diff;
  33.  
  34. }

这里对连个list的大小进行了判断,小的在最后添加,这样会减少循环里的判断,性能又有了一定的提升,正如一位朋友所说,编程是无止境的,只要你认真去思考了,总会找到更好的方法!
非常感谢binglian的指正,针对List有重复元素的问题,做以下修正,首先明确一点,两个List不管有多少个重复,只要重复的元素在两个List都能找到,则不应该包含在返回值里面,所以在做第二次循环时,这样判断:如果当前元素在map中找不到,则肯定需要添加到返回值中,如果能找到则value++,遍历完之后diff里面已经包含了只在list2里而没在list2里的元素,剩下的工作就是找到list1里有list2里没有的元素,遍历map取value为1的即可:

  1. private static List<String> getDiffrent5(List<String> list1, List<String> list2) {
  2. long st = System.nanoTime();
  3. List<String> diff = new ArrayList<String>();
  4. List<String> maxList = list1;
  5. List<String> minList = list2;
  6. if(list2.size()>list1.size())
  7. {
  8. maxList = list2;
  9. minList = list1;
  10. }
  11. Map<String,Integer> map = new HashMap<String,Integer>(maxList.size());
  12. for (String string : maxList) {
  13. map.put(string, 1);
  14. }
  15. for (String string : minList) {
  16. if(map.get(string)!=null)
  17. {
  18. map.put(string, 2);
  19. continue;
  20. }
  21. diff.add(string);
  22. }
  23. for(Map.Entry<String, Integer> entry:map.entrySet())
  24. {
  25. if(entry.getValue()==1)
  26. {
  27. diff.add(entry.getKey());
  28. }
  29. }
  30. System.out.println("getDiffrent5 total times "+(System.nanoTime()-st));
  31. return diff;
  32.  
  33. }
  1.  

Java Collection - 003 高效的找出两个List中的不同元素的更多相关文章

  1. Java - Collection 高效的找出两个List中的不同元素

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

  2. 高效的找出两个List中的不同元素

    /* * TestList.java * Version 1.0.0 * Created on 2017年12月15日 * Copyright ReYo.Cn */ package reyo.sdk. ...

  3. python——快速找出两个电子表中数据的差异

    最近刚接触python,找点小任务来练练手,希望自己在实践中不断的锻炼自己解决问题的能力. 公司里会有这样的场景:有一张电子表格的内容由两三个部门或者更多的部门用到,这些员工会在维护这些表格中不定期的 ...

  4. python:找出两个列表中相同和不同的元素(使用推导式)

    #接口返回值 list1 = ['张三', '李四', '王五', '老二'] #数据库返回值 list2 = ['张三', '李四', '老二', '王七'] a = [x for x in lis ...

  5. 使用Eclipse在Excel中找出两张表中相同证件号而姓名或工号却出现不同的的项

    1:首先把Excel中的文本复制到txt中,复制如下: A表: 证件号                           工号  姓名 310110xxxx220130004 101 傅家宜3101 ...

  6. 389. Find the Difference 找出两个字符串中多余的一个字符

    [抄题]: Given two strings s and t which consist of only lowercase letters. String t is generated by ra ...

  7. C语言:对传入sp的字符进行统计,三组两个相连字母“ea”"ou""iu"出现的次数,并将统计结果存入ct所指的数组中。-在数组中找出最小值,并与第一个元素交换位置。

    //对传入sp的字符进行统计,三组两个相连字母“ea”"ou""iu"出现的次数,并将统计结果存入ct所指的数组中. #include <stdio.h& ...

  8. 找出此产品描述中包含N个关键字的长度最短的子串

    阿里巴巴笔试题:给定一段产品的英文描述,包含M个英文字母,每个英文单词以空格分隔,无其他标点符号:再给定N个英文关键词,请说明思路并变成实现方法. String extractSummary(Stri ...

  9. FCC JS基础算法题(5):Return Largest Numbers in Arrays(找出多个数组中的最大数)

    题目描述: 找出多个数组中的最大数右边大数组中包含了4个小数组,分别找到每个小数组中的最大值,然后把它们串联起来,形成一个新数组.提示:你可以用for循环来迭代数组,并通过arr[i]的方式来访问数组 ...

随机推荐

  1. datatables 多一列报错Cannot read property 'sWidth' of undefined(…)/少一列报错Cannot read property 'style' of undefined(…)

    datatables 多一列报错Cannot read property 'sWidth' of undefined(…)/少一列报错Cannot read property 'style' of u ...

  2. LOD,听起来很牛逼的样子

    <!DOCTYPE html> <html lang="en"> <head> <title>three.js webgl - le ...

  3. SSH升级到7.7

    #!/bin/bash#删除旧版ssh包 危险操作,不删除也可以安装,建议跳过此操作.#rpm -e `rpm -qa | grep openssh` #安装zlib依赖包wget -c http:/ ...

  4. SQLI DUMB SERIES-1

    less-1 (1) 可以看到提示输入ID,而且less-1题目也有提到GET,因此试试以下操作: http: 结果: http: 结果: 现在可知,“ ' ”并没有被过滤,因此可以进行以下操作: h ...

  5. CUDA学习

    CUDA(Compute Unified Device Architecture,统一计算架构)是由NVIDIA所推出的一种集成技术,是该公司对于GPGPU的正式名称.通过这个技术,用户可利用NVID ...

  6. visual studio + opencv + contrib

    经过一天的奋战,终把opencv给用起来了.我是用的工具是vs2017+opencv3.3 上午想用mingw+opencv,结果查了很多资料说gcc不支持opencv.我感觉很奇怪,支不支持以后再说 ...

  7. 《DSP using MATLAB》Problem 6.12

    代码: %% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %% Output In ...

  8. hdu3338 Kakuro Extension 最大流

    If you solved problem like this, forget it.Because you need to use a completely different algorithm ...

  9. 浅谈malloc()和free()工作原理

    编程之路刚刚开始,错误难免,希望大家能够指出.  malloc()和free()是我经常需要用到的函数,一般情况下,C程序使用malloc()在堆上分配内存,free()释放内存,两者的参数和返回值就 ...

  10. torchvision库简介(翻译)

    部分跟新于:4.24日    torchvision 0.2.2.post3 torchvision是独立于pytorch的关于图像操作的一些方便工具库. torchvision的详细介绍在:http ...