兩個list取不同值


轉自同名博文,未知真正出處,望作者見諒

如題:有List<String> list1和List<String> list2,兩個集合各有上萬個元素,怎樣取出兩個集合中不同的元素?

方法1:遍歷兩個集合:

[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. package com.czp.test;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class TestList {  
  7.   
  8.     public static void main(String[] args) {  
  9.         List<String> list1 = new ArrayList<String>();  
  10.         List<String> list2 = new ArrayList<String>();  
  11.         for (int i = 0; i < 10000; i++) {  
  12.             list1.add("test"+i);  
  13.             list2.add("test"+i*2);  
  14.         }  
  15.         getDiffrent(list1,list2);  
  16.         //輸出:total times 2566454675  
  17.     }  
  18.   
  19.     /** 
  20.      * 獲取兩個List的不同元素 
  21.      * @param list1 
  22.      * @param list2 
  23.      * @return 
  24.      */  
  25.     private static List<String> getDiffrent(List<String> list1, List<String> list2) {  
  26.         long st = System.nanoTime();  
  27.         List<String> diff = new ArrayList<String>();  
  28.         for(String str:list1)  
  29.         {  
  30.             if(!list2.contains(str))  
  31.             {  
  32.                 diff.add(str);  
  33.             }  
  34.         }  
  35.         System.out.println("total times "+(System.nanoTime()-st));  
  36.         return diff;  
  37.     }  
  38. }  
千萬不要采用這種方法,總共要循環的次數是兩個List的size相乘的積,從輸出看耗時也是比較長的,那么我們有沒有其他的方法呢?當然有.

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

[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. package com.czp.test;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class TestList {  
  7.   
  8.     public static void main(String[] args) {  
  9.         List<String> list1 = new ArrayList<String>();  
  10.         List<String> list2 = new ArrayList<String>();  
  11.         for (int i = 0; i < 10000; i++) {  
  12.             list1.add("test"+i);  
  13.             list2.add("test"+i*2);  
  14.         }  
  15.         getDiffrent(list1,list2);  
  16.         //輸出:total times 2566454675  
  17.         getDiffrent2(list1,list2);  
  18.         //輸出:getDiffrent2 total times 2787800964  
  19.     }  
  20.       
  21.     /** 
  22.      * 獲取連個List的不同元素 
  23.      * @param list1 
  24.      * @param list2 
  25.      * @return 
  26.      */  
  27.     private static List<String> getDiffrent2(List<String> list1, List<String> list2) {  
  28.         long st = System.nanoTime();  
  29.         list1.retainAll(list2);  
  30.         System.out.println("getDiffrent2 total times "+(System.nanoTime()-st));  
  31.         return list1;  
  32.     }  
  33.   
  34.     /** 
  35.      * 獲取兩個List的不同元素 
  36.      * @param list1 
  37.      * @param list2 
  38.      * @return 
  39.      */  
  40.     private static List<String> getDiffrent(List<String> list1, List<String> list2) {  
  41.         long st = System.nanoTime();  
  42.         List<String> diff = new ArrayList<String>();  
  43.         for(String str:list1)  
  44.         {  
  45.             if(!list2.contains(str))  
  46.             {  
  47.                 diff.add(str);  
  48.             }  
  49.         }  
  50.         System.out.println("getDiffrent total times "+(System.nanoTime()-st));  
  51.         return diff;  
  52.     }  
  53. }  
  54. 很遺憾,這種方式雖然只要幾行代碼就搞定,但是這個卻更耗時,查看retainAll()的源碼:  
  55.   
  56.  public boolean retainAll(Collection<?> c) {  
  57.     boolean modified = false;  
  58.     Iterator<E> e = iterator();  
  59.     while (e.hasNext()) {  
  60.         if (!c.contains(e.next())) {  
  61.         e.remove();  
  62.         modified = true;  
  63.         }  
  64.     }  
  65.     return modified;  
  66.     }  
無需解釋這個耗時是必然的,那么我們還有沒有更好的辦法呢?仔細分析以上兩個方法中我都做了mXn次循環,其實完全沒有必要循環這么多次,我們的需求是找出兩個List中的不同元素,那么我可以這樣考慮:用一個map存放lsit的所有元素,其中的key為lsit1的各個元素,value為該元素出現的次數,接着把list2的所有元素也放到map里,如果已經存在則value加1,最后我們只要取出map里value為1的元素即可,這樣我們只需循環m+n次,大大減少了循環的次數。
[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. package com.czp.test;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. public class TestList {  
  9.   
  10.     public static void main(String[] args) {  
  11.         List<String> list1 = new ArrayList<String>();  
  12.         List<String> list2 = new ArrayList<String>();  
  13.         for (int i = 0; i < 10000; i++) {  
  14.             list1.add("test"+i);  
  15.             list2.add("test"+i*2);  
  16.         }  
  17.         getDiffrent(list1,list2);  
  18.         //輸出:total times 2566454675  
  19.         getDiffrent2(list1,list2);  
  20.         //輸出:getDiffrent2 total times 2787800964  
  21.         getDiffrent3(list1,list2);  
  22.         //輸出:getDiffrent3 total times 61763995  
  23.     }  
  24.     /** 
  25.      * 獲取兩個List的不同元素 
  26.      * @param list1 
  27.      * @param list2 
  28.      * @return 
  29.      */  
  30.     private static List<String> getDiffrent3(List<String> list1, List<String> list2) {  
  31.         long st = System.nanoTime();  
  32.         Map<String,Integer> map = new HashMap<String,Integer>(list1.size()+list2.size());  
  33.         List<String> diff = new ArrayList<String>();  
  34.         for (String string : list1) {  
  35.             map.put(string, 1);  
  36.         }  
  37.         for (String string : list2) {  
  38.             Integer cc = map.get(string);  
  39.             if(cc!=null)  
  40.             {  
  41.                 map.put(string, ++cc);  
  42.                 continue;  
  43.             }  
  44.             map.put(string, 1);  
  45.         }  
  46.         for(Map.Entry<String, Integer> entry:map.entrySet())  
  47.         {  
  48.             if(entry.getValue()==1)  
  49.             {  
  50.                 diff.add(entry.getKey());  
  51.             }  
  52.         }  
  53.         System.out.println("getDiffrent3 total times "+(System.nanoTime()-st));  
  54.         return list1;  
  55.     }  
  56.   
  57.     /** 
  58.      * 獲取兩個List的不同元素 
  59.      * @param list1 
  60.      * @param list2 
  61.      * @return 
  62.      */  
  63.     private static List<String> getDiffrent2(List<String> list1, List<String> list2) {  
  64.         long st = System.nanoTime();  
  65.         list1.retainAll(list2);  
  66.         System.out.println("getDiffrent2 total times "+(System.nanoTime()-st));  
  67.         return list1;  
  68.     }  
  69.   
  70.     /** 
  71.      * 獲取兩個List的不同元素 
  72.      * @param list1 
  73.      * @param list2 
  74.      * @return 
  75.      */  
  76.     private static List<String> getDiffrent(List<String> list1, List<String> list2) {  
  77.         long st = System.nanoTime();  
  78.         List<String> diff = new ArrayList<String>();  
  79.         for(String str:list1)  
  80.         {  
  81.             if(!list2.contains(str))  
  82.             {  
  83.                 diff.add(str);  
  84.             }  
  85.         }  
  86.         System.out.println("getDiffrent total times "+(System.nanoTime()-st));  
  87.         return diff;  
  88.     }  
  89. }  
顯然,這種方法大大減少耗時,是方法1的1/4,是方法2的1/40,這個性能的提升時相當可觀的,但是,這不是最佳的解決方法,觀察方法3我們只是隨機取了一個list作為首次添加的標准,這樣一旦我們的list2比list1的size大,則我們第二次put時的if判斷也會耗時,做如下改進:
[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. package com.czp.test;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. public class TestList {  
  9.   
  10.     public static void main(String[] args) {  
  11.         List<String> list1 = new ArrayList<String>();  
  12.         List<String> list2 = new ArrayList<String>();  
  13.         for (int i = 0; i < 10000; i++) {  
  14.             list1.add("test"+i);  
  15.             list2.add("test"+i*2);  
  16.         }  
  17.         getDiffrent(list1,list2);  
  18.         getDiffrent2(list1,list2);  
  19.         getDiffrent3(list1,list2);  
  20.         getDiffrent4(list1,list2);  
  21. //        getDiffrent total times 2789492240  
  22. //        getDiffrent2 total times 3324502695  
  23. //        getDiffrent3 total times 24710682  
  24. //        getDiffrent4 total times 15627685  
  25.     }  
  26.     /** 
  27.      * 獲取兩個List的不同元素 
  28.      * @param list1 
  29.      * @param list2 
  30.      * @return 
  31.      */  
  32.     private static List<String> getDiffrent4(List<String> list1, List<String> list2) {  
  33.         long st = System.nanoTime();  
  34.         Map<String,Integer> map = new HashMap<String,Integer>(list1.size()+list2.size());  
  35.         List<String> diff = new ArrayList<String>();  
  36.         List<String> maxList = list1;  
  37.         List<String> minList = list2;  
  38.         if(list2.size()>list1.size())  
  39.         {  
  40.             maxList = list2;  
  41.             minList = list1;  
  42.         }  
  43.         for (String string : maxList) {  
  44.             map.put(string, 1);  
  45.         }  
  46.         for (String string : minList) {  
  47.             Integer cc = map.get(string);  
  48.             if(cc!=null)  
  49.             {  
  50.                 map.put(string, ++cc);  
  51.                 continue;  
  52.             }  
  53.             map.put(string, 1);  
  54.         }  
  55.         for(Map.Entry<String, Integer> entry:map.entrySet())  
  56.         {  
  57.             if(entry.getValue()==1)  
  58.             {  
  59.                 diff.add(entry.getKey());  
  60.             }  
  61.         }  
  62.         System.out.println("getDiffrent4 total times "+(System.nanoTime()-st));  
  63.         return diff;  
  64.           
  65.     }  
  66.     /** 
  67.      * 獲取兩個List的不同元素 
  68.      * @param list1 
  69.      * @param list2 
  70.      * @return 
  71.      */  
  72.     private static List<String> getDiffrent3(List<String> list1, List<String> list2) {  
  73.         long st = System.nanoTime();  
  74.         Map<String,Integer> map = new HashMap<String,Integer>(list1.size()+list2.size());  
  75.         List<String> diff = new ArrayList<String>();  
  76.         for (String string : list1) {  
  77.             map.put(string, 1);  
  78.         }  
  79.         for (String string : list2) {  
  80.             Integer cc = map.get(string);  
  81.             if(cc!=null)  
  82.             {  
  83.                 map.put(string, ++cc);  
  84.                 continue;  
  85.             }  
  86.             map.put(string, 1);  
  87.         }  
  88.         for(Map.Entry<String, Integer> entry:map.entrySet())  
  89.         {  
  90.             if(entry.getValue()==1)  
  91.             {  
  92.                 diff.add(entry.getKey());  
  93.             }  
  94.         }  
  95.         System.out.println("getDiffrent3 total times "+(System.nanoTime()-st));  
  96.         return diff;  
  97.     }  
  98.   
  99.     /** 
  100.      * 獲取連個List的不同元素 
  101.      * @param list1 
  102.      * @param list2 
  103.      * @return 
  104.      */  
  105.     private static List<String> getDiffrent2(List<String> list1, List<String> list2) {  
  106.         long st = System.nanoTime();  
  107.         list1.retainAll(list2);  
  108.         System.out.println("getDiffrent2 total times "+(System.nanoTime()-st));  
  109.         return list1;  
  110.     }  
  111.   
  112.     /** 
  113.      * 獲取兩個List的不同元素 
  114.      * @param list1 
  115.      * @param list2 
  116.      * @return 
  117.      */  
  118.     private static List<String> getDiffrent(List<String> list1, List<String> list2) {  
  119.         long st = System.nanoTime();  
  120.         List<String> diff = new ArrayList<String>();  
  121.         for(String str:list1)  
  122.         {  
  123.             if(!list2.contains(str))  
  124.             {  
  125.                 diff.add(str);  
  126.             }  
  127.         }  
  128.         System.out.println("getDiffrent total times "+(System.nanoTime()-st));  
  129.         return diff;  
  130.     }  
  131. }  
這里對連個list的大小進行了判斷,小的在最后添加,這樣會減少循環里的判斷,性能又有了一定的提升,正如一位朋友所說,編程是無止境的,只要你認真去思考了,總會找到更好的方法!

非常感謝binglian的指正,針對List有重復元素的問題,做以下修正,首先明確一點,兩個List不管有多少個重復,只要重復的元素在兩個List都能找到,則不應該包含在返回值里面,所以在做第二次循環時,這樣判斷:如果當前元素在map中找不到,則肯定需要添加到返回值中,如果能找到則value++,遍歷完之后diff里面已經包含了只在list2里而沒在list2里的元素,剩下的工作就是找到list1里有list2里沒有的元素,遍歷map取value為1的即可:

[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. package com.czp.test;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. public class TestList {  
  9.   
  10.     public static void main(String[] args) {  
  11.         List<String> list1 = new ArrayList<String>();  
  12.         List<String> list2 = new ArrayList<String>();  
  13.         for (int i = 0; i < 10000; i++) {  
  14.             list1.add("test"+i);  
  15.             list2.add("test"+i*2);  
  16.         }  
  17.         getDiffrent(list1,list2);  
  18.         getDiffrent3(list1,list2);  
  19.         getDiffrent5(list1,list2);  
  20.         getDiffrent4(list1,list2);  
  21.         getDiffrent2(list1,list2);  
  22.   
  23. //        getDiffrent3 total times 32271699  
  24. //        getDiffrent5 total times 12239545  
  25. //        getDiffrent4 total times 16786491  
  26. //        getDiffrent2 total times 2438731459  
  27.           
  28.     }  
  29.     /** 
  30.      * 獲取兩個List的不同元素 
  31.      * @param list1 
  32.      * @param list2 
  33.      * @return 
  34.      */  
  35.     private static List<String> getDiffrent5(List<String> list1, List<String> list2) {  
  36.         long st = System.nanoTime();  
  37.          List<String> diff = new ArrayList<String>();  
  38.          List<String> maxList = list1;  
  39.          List<String> minList = list2;  
  40.          if(list2.size()>list1.size())  
  41.          {  
  42.              maxList = list2;  
  43.              minList = list1;  
  44.          }  
  45.          Map<String,Integer> map = new HashMap<String,Integer>(maxList.size());  
  46.          for (String string : maxList) {  
  47.              map.put(string, 1);  
  48.          }  
  49.          for (String string : minList) {  
  50.              if(map.get(string)!=null)  
  51.              {  
  52.                  map.put(string, 2);  
  53.                  continue;  
  54.              }  
  55.              diff.add(string);  
  56.          }  
  57.          for(Map.Entry<String, Integer> entry:map.entrySet())  
  58.          {  
  59.              if(entry.getValue()==1)  
  60.              {  
  61.                  diff.add(entry.getKey());  
  62.              }  
  63.          }  
  64.         System.out.println("getDiffrent5 total times "+(System.nanoTime()-st));  
  65.         return diff;  
  66.           
  67.     }  
  68.     /** 
  69.      * 獲取兩個List的不同元素 
  70.      * @param list1 
  71.      * @param list2 
  72.      * @return 
  73.      */  
  74.     private static List<String> getDiffrent4(List<String> list1, List<String> list2) {  
  75.         long st = System.nanoTime();  
  76.         Map<String,Integer> map = new HashMap<String,Integer>(list1.size()+list2.size());  
  77.         List<String> diff = new ArrayList<String>();  
  78.         List<String> maxList = list1;  
  79.         List<String> minList = list2;  
  80.         if(list2.size()>list1.size())  
  81.         {  
  82.             maxList = list2;  
  83.             minList = list1;  
  84.         }  
  85.         for (String string : maxList) {  
  86.             map.put(string, 1);  
  87.         }  
  88.         for (String string : minList) {  
  89.             Integer cc = map.get(string);  
  90.             if(cc!=null)  
  91.             {  
  92.                 map.put(string, ++cc);  
  93.                 continue;  
  94.             }  
  95.             map.put(string, 1);  
  96.         }  
  97.         for(Map.Entry<String, Integer> entry:map.entrySet())  
  98.         {  
  99.             if(entry.getValue()==1)  
  100.             {  
  101.                 diff.add(entry.getKey());  
  102.             }  
  103.         }  
  104.         System.out.println("getDiffrent4 total times "+(System.nanoTime()-st));  
  105.         return diff;  
  106.           
  107.     }  
  108.     /** 
  109.      * 獲取兩個List的不同元素 
  110.      * @param list1 
  111.      * @param list2 
  112.      * @return 
  113.      */  
  114.     private static List<String> getDiffrent3(List<String> list1, List<String> list2) {  
  115.         long st = System.nanoTime();  
  116.         Map<String,Integer> map = new HashMap<String,Integer>(list1.size()+list2.size());  
  117.         List<String> diff = new ArrayList<String>();  
  118.         for (String string : list1) {  
  119.             map.put(string, 1);  
  120.         }  
  121.         for (String string : list2) {  
  122.             Integer cc = map.get(string);  
  123.             if(cc!=null)  
  124.             {  
  125.                 map.put(string, ++cc);  
  126.                 continue;  
  127.             }  
  128.             map.put(string, 1);  
  129.         }  
  130.         for(Map.Entry<String, Integer> entry:map.entrySet())  
  131.         {  
  132.             if(entry.getValue()==1)  
  133.             {  
  134.                 diff.add(entry.getKey());  
  135.             }  
  136.         }  
  137.         System.out.println("getDiffrent3 total times "+(System.nanoTime()-st));  
  138.         return diff;  
  139.     }  
  140.   
  141.     /** 
  142.      * 獲取連個List的不同元素 
  143.      * @param list1 
  144.      * @param list2 
  145.      * @return 
  146.      */  
  147.     private static List<String> getDiffrent2(List<String> list1, List<String> list2) {  
  148.         long st = System.nanoTime();  
  149.         list1.retainAll(list2);  
  150.         System.out.println("getDiffrent2 total times "+(System.nanoTime()-st));  
  151.         return list1;  
  152.     }  
  153.   
  154.     /** 
  155.      * 獲取兩個List的不同元素 
  156.      * @param list1 
  157.      * @param list2 
  158.      * @return 
  159.      */  
  160.     private static List<String> getDiffrent(List<String> list1, List<String> list2) {  
  161.         long st = System.nanoTime();  
  162.         List<String> diff = new ArrayList<String>();  
  163.         for(String str:list1)  
  164.         {  
  165.             if(!list2.contains(str))  
  166.             {  
  167.                 diff.add(str);  
  168.             }  
  169.         }  
  170.         System.out.println("getDiffrent total times "+(System.nanoTime()-st));  
  171.         return diff;  
  172.     }  
  173. }  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM