最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java找出兩個大數(shù)據(jù)量List集合中的不同元素的方法總結(jié)

 更新時間:2022年10月23日 16:23:30   作者:共飲一杯無  
本文將帶大家了解如何快速的找出兩個相似度非常高的List集合里的不同元素。主要通過Java API、List集合雙層遍歷比較不同、借助Map集合查找三種方式,需要的可以參考一下

本文將帶你了解如何快速的找出兩個相似度非常高的List集合里的不同元素。主要通過Java API、List集合雙層遍歷比較不同、借助Map集合查找三種方式,以及他們之間的執(zhí)行效率情況,話不多說,開搞! 集合初始化方法:

    /**
     * 制造任意個元素的的List集合
     * @param size List集合的size
     * @return List<String>
     */
    private static List<String> dataList(int size) {
        List<String> dataList = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            dataList.add("" + i);
        }
        return dataList;
    }

測試數(shù)據(jù)為集合A: 1千, 1萬, 10萬,1百萬, 1千萬的數(shù)據(jù)量.

  • 集合B比集合A多初始化六條數(shù)據(jù),集合A添加一條特有的數(shù)據(jù)。
  • 測試數(shù)據(jù)使用空字符串 + 自然數(shù)的方式。

JavaAPI過濾(不推薦)

1千數(shù)據(jù)量

        List<String> listA = dataList(1000);
        //集合A添加一個集合B沒有的元素
        listA.add("onlyA10086");
        List<String> listB = dataList(1006);
        Long startTime = System.currentTimeMillis();
        // 復(fù)制集合A和集合B作為備份
        List<String> listABak = new ArrayList<>(listA);
        List<String> listBBak = new ArrayList<>(listB);
        // 集合B存在,集合A不存在的元素
        listB.removeAll(listA);
        // 集合A存在,集合B不存在的元素
        listA.removeAll(listBBak);
        Long endTime = System.currentTimeMillis();
        List<String> differentList = new ArrayList<>();
        differentList.addAll(listB);
        differentList.addAll(listA);
        System.out.println("集合A和集合B不同的元素:"+differentList);
        Long costTime = endTime-startTime;
        System.out.println("比對耗時:"+costTime+"毫秒。");

耗時:22毫秒

1萬數(shù)據(jù)量

        List<String> listA = dataList(10000);
        //集合A添加一個集合B沒有的元素
        listA.add("onlyA10086");
        List<String> listB = dataList(10006);
        Long startTime = System.currentTimeMillis();
        // 復(fù)制集合A和集合B作為備份
        List<String> listABak = new ArrayList<>(listA);
        List<String> listBBak = new ArrayList<>(listB);
        // 集合B存在,集合A不存在的元素
        listB.removeAll(listA);
        // 集合A存在,集合B不存在的元素
        listA.removeAll(listBBak);
        Long endTime = System.currentTimeMillis();
        List<String> differentList = new ArrayList<>();
        differentList.addAll(listB);
        differentList.addAll(listA);
        System.out.println("集合A和集合B不同的元素:"+differentList);
        Long costTime = endTime-startTime;
        System.out.println("比對耗時:"+costTime+"毫秒。");

耗時:613毫秒

10萬數(shù)據(jù)量

        List<String> listA = dataList(100000);
        //集合A添加一個集合B沒有的元素
        listA.add("onlyA10086");
        List<String> listB = dataList(100006);
        Long startTime = System.currentTimeMillis();
        // 復(fù)制集合A和集合B作為備份
        List<String> listABak = new ArrayList<>(listA);
        List<String> listBBak = new ArrayList<>(listB);
        // 集合B存在,集合A不存在的元素
        listB.removeAll(listA);
        // 集合A存在,集合B不存在的元素
        listA.removeAll(listBBak);
        Long endTime = System.currentTimeMillis();
        List<String> differentList = new ArrayList<>();
        differentList.addAll(listB);
        differentList.addAll(listA);
        System.out.println("集合A和集合B不同的元素:"+differentList);
        Long costTime = endTime-startTime;
        System.out.println("比對耗時:"+costTime+"毫秒。");

可以看出來十萬數(shù)據(jù)量級別已經(jīng)比較慢了,需要77秒

100萬數(shù)據(jù)量

emmm估計挺慢,不繼續(xù)驗證了。

為什么在數(shù)據(jù)量增大的時候,這種方法性能下降的這么明顯? 我們不妨來看一下removeAll的源碼:

    public boolean removeAll(Collection<?> c) {
        // 先判空,然后執(zhí)行批量remove
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }

通過源碼我們可以看到,該方法是使用for循環(huán)對集合進行遍歷 第一層循環(huán)需要執(zhí)行 listA.size()次,里面調(diào)用了contains方法來確定集合B是否含有該元素, 再看contains方法的源碼:

可以看到,indexOf方法里又進行了一層遍歷. 平均每次遍歷要進行l(wèi)ist.size() / 2次計算, 假設(shè)集合A的元素個數(shù)為m,集合B的元素個數(shù)為n 我們可以得到結(jié)論,運算次數(shù)為 m *(n/2) 對于100W數(shù)據(jù)量來說,假設(shè)你的計算機每秒能夠執(zhí)行1千萬次運算,也需要13.8個小時才能對比出來。所以大數(shù)據(jù)量不建議通過此方法。

List集合雙層遍歷比較不同(不推薦)

該方法實際上就是將removeAll的實現(xiàn)邏輯用自己的方式寫出來,所以執(zhí)行效率,運行結(jié)果和上一種方法沒什么區(qū)別,這里只貼代碼出來,不再贅述。

private static void doubleFor() {
        List<String> listA = dataList(1000);
        //集合A添加一個集合B沒有的元素
        listA.add("onlyA10086");
        List<String> listB = dataList(1006);
        System.out.println("數(shù)量級為 " + listA.size() + "集合的不同元素為");
        List<String> differentList = new ArrayList<>();
        long startTime = System.currentTimeMillis();
        for (String str : listB) {
            if (!listA.contains(str)) {
                differentList.add(str);
            }
        }
        for (String str : listA) {
            if (!listB.contains(str)) {
                differentList.add(str);
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("集合A和集合B不同的元素:"+differentList);
        System.out.println("使用雙層遍歷方法 比對耗時: " + (endTime - startTime)+"毫秒。");
    }

以上兩個方法中我都做了m*n次循環(huán),其實完全沒有必要循環(huán)這么多次,我們的需求是找出兩個List中的不同元素,那么我可以這樣考慮:用一個map存放lsit的所有元素,其中的key為lsit1的各個元素,value為該元素出現(xiàn)的次數(shù),接著把list2的所有元素也放到map里,如果已經(jīng)存在則value加1,最后我們只要取出map里value為1的元素即可,這樣我們只需循環(huán)m+n次,大大減少了循環(huán)的次數(shù)。

借助Map集合查找(推薦)

以List集合里的元素作為Map的key,元素出現(xiàn)的次數(shù)作為Map的Value,那么兩個List集合的不同元素在Map集合中value值為1,所對應(yīng)的鍵。把所有value值為1的鍵找出來,我們就得到了兩個List集合不同的元素。 代碼如下:

    /**
     * 借助Map來獲取listA、listB的不同元素集合
     *
     * @param listA 集合A
     * @param listB 集合B
     * @return list<String> 不同元素集合
     */
    public static List<String> getDifferListByMap(List<String> listA, List<String> listB) {
        List<String> differList = new ArrayList<>();
        Map<String, Integer> map = new HashMap<>();
        long beginTime = System.currentTimeMillis();
        for (String strA : listA) {
            map.put(strA, 1);
        }
        for (String strB : listB) {
            Integer value = map.get(strB);
            if (value != null) {
                map.put(strB, ++value);
                continue;
            }
            map.put(strB, 1);
        }

        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            //獲取不同元素集合
            if (entry.getValue() == 1) {
                differList.add(entry.getKey());
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("集合A和集合B不同的元素:"+differList);
        System.out.println("使用map方式遍歷, 對比耗時: " + (endTime - beginTime)+"毫秒。");
        return differList;
    }

1千數(shù)據(jù)量

        List<String> listA = dataList(1000);
        //集合A添加一個集合B沒有的元素
        listA.add("onlyA10086");
        List<String> listB = dataList(1006);
        getDifferListByMap(listA,listB);

耗時:7毫秒

1萬數(shù)據(jù)量

        List<String> listA = dataList(10000);
        //集合A添加一個集合B沒有的元素
        listA.add("onlyA10086");
        List<String> listB = dataList(10006);
        getDifferListByMap(listA,listB);

耗時:42毫秒

10萬數(shù)據(jù)量

        List<String> listA = dataList(100000);
        //集合A添加一個集合B沒有的元素
        listA.add("onlyA10086");
        List<String> listB = dataList(100006);
        getDifferListByMap(listA,listB);

耗時:130毫秒

100萬數(shù)據(jù)量

        List<String> listA = dataList(1000000);
        //集合A添加一個集合B沒有的元素
        listA.add("onlyA10086");
        List<String> listB = dataList(1000006);
        getDifferListByMap(listA,listB);

耗時:283毫秒

1000萬數(shù)據(jù)量

        List<String> listA = dataList(10000000);
        //集合A添加一個集合B沒有的元素
        listA.add("onlyA10086");
        List<String> listB = dataList(10000006);
        getDifferListByMap(listA,listB);

耗時:6.6秒

可以看出來這種方法相當(dāng)高效,千萬級數(shù)據(jù)比對也才用了6.6秒。 使用map集合的方式尋找不同元素,時間增長基本上是線性的,它的時間復(fù)雜度為O(m)。 而上面的remove方式和雙層循環(huán)遍歷的時間復(fù)雜度為O(m * n)。 所以,選用這種方式帶來的性能收益隨著集合元素的增長而增長。

優(yōu)化

上述通過map集合的方式效率很高,有沒有可以優(yōu)化的點呢?

  • 兩個集合如果數(shù)量差距較大時,可以把小的在后面添加,這樣會減少循環(huán)里的判斷,性能又有了一定的提升。
  • 創(chuàng)建map集合的時候直接指定大小,防止再散列。

優(yōu)化后代碼如下:

    /**
     * 找出兩個集合中不同的元素
     *
     * @param collmax
     * @param collmin
     * @return
     */
    public static Collection getDifferListByMapPlus(Collection collmax, Collection collmin) {
        //使用LinkedList防止差異過大時,元素拷貝
        Collection csReturn = new LinkedList();
        Collection max = collmax;
        Collection min = collmin;
        long beginTime = System.currentTimeMillis();
        //先比較大小,這樣會減少后續(xù)map的if判斷次數(shù)
        if (collmax.size() < collmin.size()) {
            max = collmin;
            min = collmax;
        }
        //直接指定大小,防止再散列
        Map<Object, Integer> map = new HashMap<Object, Integer>(max.size());
        for (Object object : max) {
            map.put(object, 1);
        }
        for (Object object : min) {
            if (map.get(object) == null) {
                csReturn.add(object);
            } else {
                map.put(object, 2);
            }
        }
        for (Map.Entry<Object, Integer> entry : map.entrySet()) {
            if (entry.getValue() == 1) {
                csReturn.add(entry.getKey());
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("集合A和集合B不同的元素:"+csReturn);
        System.out.println("使用map方式遍歷, 對比耗時: " + (endTime - beginTime)+"毫秒。");
        return csReturn;
    }

找出相同元素

同樣找出相同元素可以使用如下代碼:

    /**
     * 找出兩個集合中相同的元素
     *
     * @param collmax
     * @param collmin
     * @return
     */
    public static Collection getSameListByMap(Collection collmax, Collection collmin) {
        //使用LinkedList防止差異過大時,元素拷貝
        Collection csReturn = new LinkedList();
        Collection max = collmax;
        Collection min = collmin;
        //先比較大小,這樣會減少后續(xù)map的if判斷次數(shù)
        if (collmax.size() < collmin.size()) {
            max = collmin;
            min = collmax;
        }
        //直接指定大小,防止再散列
        Map<Object, Integer> map = new HashMap<Object, Integer>(max.size());
        for (Object object : max) {
            map.put(object, 1);
        }
        for (Object object : min) {
            if (map.get(object) != null) {
                csReturn.add(object);
            }
        }
        return csReturn;
    }

以上就是Java找出兩個大數(shù)據(jù)量List集合中的不同元素的方法總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Java找出List集合中的不同元素的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot整合MybatisPlus的基本應(yīng)用指南

    SpringBoot整合MybatisPlus的基本應(yīng)用指南

    MyBatis-Plus ,簡稱 MP,是一個 MyBatis的增強工具,在 MyBatis 的基礎(chǔ)上只做增強不做改變,下面小編就來和大家介紹一下SpringBoot整合MybatisPlus的一些基本應(yīng)用吧
    2025-03-03
  • Spring Boot2.X國際化文件編寫配置

    Spring Boot2.X國際化文件編寫配置

    這篇文章主要介紹了Spring Boot2.X國際化文件編寫配置,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • sprintboot使用spring-security包,緩存內(nèi)存與redis共存方式

    sprintboot使用spring-security包,緩存內(nèi)存與redis共存方式

    這篇文章主要介紹了sprintboot使用spring-security包,緩存內(nèi)存與redis共存方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • java中將一個實體類復(fù)制到另一個實體類的3種方法示例

    java中將一個實體類復(fù)制到另一個實體類的3種方法示例

    這篇文章主要給大家介紹了關(guān)于java中將一個實體類復(fù)制到另一個實體類的3種方法,所謂實體類就是一個擁有Set和Get方法的類,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • Java學(xué)習(xí)之Lambda表達式的使用詳解

    Java學(xué)習(xí)之Lambda表達式的使用詳解

    Lambda表達式是Java SE 8中一個重要的新特性,允許通過表達式來代替功能接口。本文將通過一些簡單的示例和大家講講Lamda表達式的使用,感興趣的可以了解一下
    2022-12-12
  • Java ArrayList擴容機制原理深入分析

    Java ArrayList擴容機制原理深入分析

    在Java中,ArrayList是最常用的集合之一。它是一種容器,它的內(nèi)部定義了一個Object類型的數(shù)組elementData,因此可用于存儲任意類型的數(shù)據(jù)。我們知道,數(shù)組是長度恒定的。而ArrayList相當(dāng)于是一個長度可變的動態(tài)數(shù)組,一起來看看的它的擴容機制
    2023-02-02
  • SpringBoot2.x中management.security.enabled=false無效的解決

    SpringBoot2.x中management.security.enabled=false無效的解決

    這篇文章主要介紹了SpringBoot2.x中management.security.enabled=false無效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 使用Gradle做Java代碼質(zhì)量檢查的方法示例

    使用Gradle做Java代碼質(zhì)量檢查的方法示例

    這篇文章主要介紹了使用Gradle做Java代碼質(zhì)量檢查的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-03-03
  • springboot的SpringPropertyAction事務(wù)屬性源碼解讀

    springboot的SpringPropertyAction事務(wù)屬性源碼解讀

    這篇文章主要介紹了springboot的SpringPropertyAction事務(wù)屬性源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • 基于Spring的RPC通訊模型的使用與比較

    基于Spring的RPC通訊模型的使用與比較

    這篇文章主要介紹了基于Spring的RPC通訊模型的使用與比較,詳細(xì)的介紹了RMI、Caucho的Hessian和Burlap以及Spring自帶的HTTP invoker,感興趣的可以了解一下
    2018-09-09

最新評論

白银市| 克东县| 侯马市| 马尔康县| 宁阳县| 新郑市| 丽江市| 湘潭市| 平阴县| 太白县| 平顶山市| 福鼎市| 兴隆县| 天水市| 海盐县| 彩票| 青神县| 苏州市| 金堂县| 桐城市| 合水县| 修武县| 侯马市| 集安市| 木里| 武义县| 嘉定区| 崇州市| 醴陵市| 南阳市| 海林市| 东丰县| 太保市| 苍南县| 灵山县| 湄潭县| 耿马| 新郑市| 嘉荫县| 新平| 林西县|