zoukankan      html  css  js  c++  java
  • 两个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. }  
  • 相关阅读:
    Minimum Depth of Binary Tree leetcode java
    Maximum Depth of Binary Tree leetcode java
    Symmetric Tree leetcode java
    Same Tree leetcode java
    Binary Tree Postorder Traversal leetcode java
    Binary Tree Preorder Traversal leetcode java
    Binary Tree Inorder Traversal leetcode java
    Combinations leetcode java
    一键清除Centos iptables 防火墙所有规则
    阿里云centos7.7x64安装open,并配置ip转发和nat伪装
  • 原文地址:https://www.cnblogs.com/handbang/p/6209433.html
Copyright © 2011-2022 走看看