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


    如题:有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;
        }
    }
  • 相关阅读:
    动态规划 简单的分割问题的解决方案钢棒
    SICP 1.20经验
    辛星一起了解下后续PHP性能功能
    汽车之家购买价格PC真正的原因阿拉丁
    可怜,的分母。
    [ACM] poj 1064 Cable master (二进制搜索)
    从Access创建Sqlite数据库
    变化的阅读程序猿自学习
    ArcEngine载入中SDE问题栅格数据
    pinyin4j新手教程
  • 原文地址:https://www.cnblogs.com/zq-boke/p/6245621.html
Copyright © 2020-2023  润新知