快速找出List集合的相同与不同元素集合

今天来比较一下两个list,然后分别找出相同元素和不同元素的集合。
先上一个简单的示例:(注:因为测试数据量比较小,用ArrayList,如果涉及到百万数据的插入移除操作的话,用LinkedList)

[java]  view plain  copy
  1. <span style="white-space:pre">    </span>   List<String> listA = new ArrayList<String>();  
  2.    List<String> listB = new ArrayList<String>();  
  3.    for(int i=0;i<6){  
  4.     listA.add(i+"");//0,1,2,3,4,5  
  5.     listB.add(i+1+"");//1,2,3,4,5,6  
  6.    }  
  7.           List<String> listC = getDifferListByLoop(listA,listB);//这里调用获取相同、不同元素集合的方法  
  8.    Object[] strArray =  listC.toArray();  
  9.    System.out.println("same ele is :  "+Arrays.toString(strArray));  
首先,求出这两个集合的相同元素,第一个想法当然就是定义一个listC,然后两个AB集合分别循环取值判断,如果有相等的话,就放入这个listC。来,我们看看这个方案:
[java]  view plain  copy
  1. /** 
  2.   * 双循环获取listA、listB的相同元素集合 
  3.   * @param listA 
  4.   * @param listB 
  5.   * @return list<String> 
  6.   */  
  7.  public static List<String> getSameListByLoop(List<String> listA,List<String> listB){  
  8.      long begin = System.nanoTime();//纳秒  
  9.      List<String> listC = new ArrayList<String>();  
  10.      for(String str :listA){  
  11.          if(listB.contains(str)){  
  12.              listC.add(str);  
  13.          }  
  14.      }  
  15.      long end = System.nanoTime();  
  16.      System.out.println("take  " + (end-begin) + " time ");  
  17.      return listC;  
  18.  }  
输出:
take  79110 time 
same ele is :  [1, 2, 3, 4, 5]

输出没有问题。同理,如果是求出不同元素的话,也是定义一个ListC,遍历循环listA和listB,把不相等的值放入listC,如下:

[java]  view plain  copy
  1. /** 
  2.   * 双循环获取listA、listB的不同元素集合 
  3.   * @param listA 
  4.   * @param listB 
  5.   * @return list<String> 
  6.   */  
  7.  public static List<String> getDifferListByLoop(List<String> listA,List<String> listB){  
  8.      long begin = System.nanoTime();//纳秒  
  9.      List<String> listC = new ArrayList<String>();  
  10.      for(String str :listA){  
  11.          if(!listB.contains(str)){  
  12.              listC.add(str);  
  13.          }  
  14.      }  
  15.      long end = System.nanoTime();  
  16.      System.out.println(" take " + (end-begin) + " time ");  
  17.      return listC;  
  18.  }  
输出:
take 50032 time 
different ele is :  [0]
哎?输出应该是[0,6]才对呀,哦,不对,求不同元素的时候只遍历了listA,判断了ListB中是否包含ListA的元素,如果listB中有的元素不在ListA中,是判断不出来的。因此,还要再加一段:
[java]  view plain  copy
  1. for(String str :listB){  
  2. if(!listA.contains(str)){  
  3. listC.add(str);  
  4. }  
  5. }  
这样就对了,输出:
take 56019 time 
different ele is :  [0, 6]

这样是不是就行了呢,当然不行。
我们知道,一般业务场景下list集合里可能会有大量的数据,如果连用两个循环遍历(contains的操作也是for循环遍历),时间复杂度是O(m*n)[m,n分别是listA、listB的长度],可想而知,效率很低下。那么怎么解决这个问题呢?
想一下,是不是可以用Map来解决这个问题呢?如果把这两个list的值分别作为Map的key值,value为该元素出现的次数。如下:
[java]  view plain  copy
  1. /** 
  2.   * 使用Map来获取listA、listB的不同元素集合 
  3.   * @param listA 
  4.   * @param listB 
  5.   * @return list<String> 
  6.   */  
  7.  public static List<String> getDifferListByMap(List<String> listA,List<String> listB){  
  8.      long begin = System.nanoTime();//纳秒  
  9.      List<String> listC = new ArrayList<String>();  
  10.      Map<String,Integer> map = new HashMap<String,Integer>();  
  11.      for(String strA:listA){  
  12.          map.put(strA, 1);  
  13.      }  
  14.      for(String strB:listB){  
  15.          Integer value = map.get(strB);  
  16.          if(value != null){  
  17.              map.put(strB, ++value);  
  18.              continue;  
  19.          }  
  20.          map.put(strB, 1);  
  21.      }  
  22.        
  23.      for(Map.Entry<String, Integer> entry:map.entrySet()){  
  24.         if(entry.getValue()==1){//获取不同元素集合  
  25.             listC.add(entry.getKey());  
  26.         }  
  27.      }  
  28.      long end = System.nanoTime();  
  29.      System.out.println("take " + (end-begin) + " time ");  
  30.      return listC;  //亲测有效
  31.  }  
输出 :
take 564456 time 
different ele is :  [0, 6]

当数据量大的时候时间明显时间要小很多,可以把list里的i换成10000,前后两种求不同元素的方法输出时间为:
第一种:take 585109053 time 
different ele is :  [0, 10000]

第二种:take 31576607 time 
different ele is :  [0, 10000]

差异就明显了。同理,求出相同元素的集合只要value!=1就可以了。

参考:
http://www.cnblogs.com/czpblog/archive/2012/08/06/2625794.html 
     

never too late!          

原文地址: https://blog.csdn.net/maoyeqiu/article/details/48750953

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值