范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

大数组元素差异比较下的removeAll和Map效率对比

  考虑这样一个场景,对两个列表对象,listA 和 listB,比较二者差异,找出只在 listA 中出现的元素列表 onlyListA,找出只在 listB 中出现的元素列表 onlyListB。removeAll实现
  很容易想到借助 removeAll 实现,代码如下。List listA = new ArrayList<>(); List listB = new ArrayList<>();   //仅在数组A中出现的元素 List onlyListA = new ArrayList<>(listA); onlyListA.removeAll(listB);  //仅在数组B中出现的元素 List onlyListB = new ArrayList<>(listB); onlyListB.removeAll(listA); 复制代码
  当数组元素较少时,借助 removeAll 实现并没有任何问题。不过在数组元素较大时,removeAll 方法耗时会较大。执行如下测试方法,对数组元素个数为1000,1W,10W,100W 的场景进行测试。public class ListDiffTest {      public static void main(String[] args) {         testRemoveAllCostTime(1000);         testRemoveAllCostTime(10000);         testRemoveAllCostTime(100000);         testRemoveAllCostTime(1000000);     }          public static void testRemoveAllCostTime(int size) {          List listA = dataList(size);         listA.add("onlyAElement");          List listB = dataList(size + 3);          long startTime = System.currentTimeMillis();          //仅在数组A中出现的元素         List onlyListA = new ArrayList<>(listA);         onlyListA.removeAll(listB);          //仅在数组B中出现的元素         List onlyListB = new ArrayList<>(listB);         onlyListB.removeAll(listA);          System.out.println("仅在集合A中出现的元素:" + onlyListA);         System.out.println("仅在集合B中出现的元素:" + onlyListB);         System.out.println("元素个数 = " + size + "时,比对耗时:" +  (System.currentTimeMillis() - startTime) + " 毫秒");     }      private static List dataList(int size) {         List dataList = new ArrayList<>();         for (int i = 0; i < size; i++) {             dataList.add("" + i);         }         return dataList;     } } 复制代码
  测试结果如下仅在集合A中出现的元素:[onlyAElement] 仅在集合B中出现的元素:[1000, 1001, 1002]  元素个数 = 1000时,比对耗时:19 毫秒    元素个数 = 10000时,比对耗时:299 毫秒   #1W  元素个数 = 100000时,比对耗时:24848 毫秒   #10W  元素个数 = 1000000时,比对耗时:3607607 毫秒   #100W 约60m 复制代码
  可以看到,当数组元素达到百万级时,耗时将达60min上下。借助Map实现
  此处给出一种优化方式,借助 Map 计数,将 List 集合中的元素作为 Map 的 key,元素出现的次数作为 Map 的 value。代码实现如下。import io.vavr.Tuple2;  public class ListDiffTest {      public static void main(String[] args) {         testDifferListByMapCostTime(1000);         testDifferListByMapCostTime(10000);         testDifferListByMapCostTime(100000);         testDifferListByMapCostTime(1000000);     }       public static void testDifferListByMapCostTime(int size) {          List listA = dataList(size);         listA.add("onlyAElement");          List listB = dataList(size + 3);          long startTime = System.currentTimeMillis();          //仅在数组A中出现的元素         List onlyListA = tuple2._1;;          //仅在数组B中出现的元素         List onlyListB = tuple2._2;          System.out.println("仅在集合A中出现的元素:" + onlyListA);         System.out.println("仅在集合B中出现的元素:" + onlyListB);         System.out.println("元素个数 = " + size + "时,比对耗时:" +  (System.currentTimeMillis() - startTime) + " 毫秒");       }       /**      * 通过Map计数方式 比较两个数组之间的差异      *      * @param listA 数组A      * @param listB 数组B      * @param  元素类型      * @return Tuple2对象 onlyAList-只在数组A存在的元素  onlyBList-只在数组B存在的元素      */     public static  Tuple2, List> getDiffListBtMapCompare(List listA, List listB) {         ValidateUtils.validateNotNull(listA, "listA");         ValidateUtils.validateNotNull(listB, "listB");          List onlyAList = new ArrayList<>();         List onlyBList = new ArrayList<>();          if (CollectionUtils.isEmpty(listA)) {             return Tuple.of(onlyAList, listB);         } else if (CollectionUtils.isEmpty(listB)) {             return Tuple.of(listA, onlyBList);         }          /**          * listA中元素 初始化计数 = 1          * listB中元素 初始化计数 = -2          * 遍历累加后          * 相同元素 计数 = 2          * 仅A中出现元素  计数 = 1          * 仅A中出现元素  计数 = -1          */         Map countMap = new HashMap<>(Math.max(listA.size(), listB.size()));         for (E eleA : listA) {             countMap.put(eleA, 1);         }          for (E eleB : listB) {             countMap.put(eleB, 1 + countMap.getOrDefault(eleB, -2));         }          countMap.forEach((k, v) -> {             //获取不同元素集合             if (v == 1) {                 onlyAList.add(k);             } else if (v == -1) {                 onlyBList.add(k);             }         });          return Tuple.of(onlyAList, onlyBList);     } } 复制代码
  测试结果如下仅在集合A中出现的元素:[onlyAElement] 仅在集合B中出现的元素:[1000, 1002, 1001]  元素个数 = 1000时,比对耗时:8 毫秒  元素个数 = 10000时,比对耗时:19 毫秒   #1W  元素个数 = 100000时,比对耗时:28 毫秒  #10W  元素个数 = 1000000时,比对耗时:96 毫秒  #100W  元素个数 = 10000000时,比对耗时:5320 毫秒  #1000W  复制代码removeAll耗时分析
  最后,来分析下为什么在大数组元素比较时,removeAll 性能较差。removeAll 方法中,先进行判空,然后调用 batchRemove() 方法    public boolean removeAll(Collection<?> c) {         Objects.requireNonNull(c);         return batchRemove(c, false);     } 复制代码batchRemove() 方法中,使用 for 循环对集合进行遍历。第 1 层循环需要执行 listA.size() 次。循环体中调用了 contains() 方法来确定集合 B 是否含有该元素。    private boolean batchRemove(Collection<?> c, boolean complement) {         final Object[] elementData = this.elementData;         int r = 0, w = 0;         boolean modified = false;         try {             for (; r < size; r++)                 if (c.contains(elementData[r]) == complement)                     elementData[w++] = elementData[r];         } finally {             // Preserve behavioral compatibility with AbstractCollection,             // even if c.contains() throws.             if (r != size) {                 System.arraycopy(elementData, r,                                  elementData, w,                                  size - r);                 w += size - r;             }             if (w != size) {                 // clear to let GC do its work                 for (int i = w; i < size; i++)                     elementData[i] = null;                 modCount += size - w;                 size = w;                 modified = true;             }         }         return modified;     } 复制代码contains() 方法的实现如下,内部又调用了 indexOf() 方法。indexOf() 方法内部又进行了一层 for 循环遍历。    public boolean contains(Object o) {         return indexOf(o) >= 0;     }      public int indexOf(Object o) {         if (o == null) {             for (int i = 0; i < size; i++)                 if (elementData[i]==null)                     return i;         } else {             for (int i = 0; i < size; i++)                 if (o.equals(elementData[i]))                     return i;         }         return -1;     } 复制代码至此,可以看到,按照平均每次遍历要进行 list.size() / 2 次计算,假设集合 A 的元素个数为 m,集合 B 的元素个数为 n,则两重 for 循环下,会执行 m*n/2次。对于两个千万量级的数组,将执行 100 亿次计算!!!
  由此给出一个结论,对于大数组元素差异比较,不建议使用 removeAll,可以借助 Map 实现。
  原文链接:https://juejin.cn/post/7208099962911752247

央行开展300亿元逆回购操作,本周净投放1900亿元中新经纬3月18日电央行官网公告,为维护银行体系流动性合理充裕,2022年3月18日人民银行以利率招标方式开展了300亿元逆回购操作,中标利率2。10。Wind数据显示,18日10弟弟为什么要我来养!51岁阿姨坚持高龄产子,葬送女儿的幸福随着二胎三胎政策的相继开放,许多父母的心思都动了起来,出于各种各样的目的,他们开始计划着再生个孩子。然而,不管父母是什么心态,生孩子这件事要是没有得到第一个孩子的认可,那最后的结果刘强东全家同游三亚,章泽天陪5岁女儿玩滑梯,一家三口超幸福近日,有网友晒出前段时间,在三亚某酒店偶遇刘强东章泽天一家三口出游的画面,画面中能够看到,章泽天提着大包,烫着大卷发,抬着头看着正在玩儿滑梯的女儿。5岁的女儿很是可爱,已经能够独自唐嫣夫妇罕见撒糖!罗晋亲自开车接老婆回家,肚腩明显惊现幸福肥?3月16日,某八卦媒体在社交网站上晒出了唐嫣夫妇的近况,表示唐嫣此前在拍摄工作中,突然被隔离,结束48小时隔离后,老公罗晋亲自开车去接她回家。据了解,唐嫣此前独自开车去某摄影棚拍广人生,由我不由天,幸福,由心不由境得知坦然,失之淡然,争之必然,顺其自然。人生不如意事十之八九,凡事不必太过认真,不要太过强求。一切随缘,顺其自然就好。命里有时终须有,命里无时莫强求。的确,这是一个尔虞我诈,充满竞歌后韦唯嫁错人毁一生,3个儿子让她晚年幸福这是心的呼唤,这是爱的奉献这是人间的春风,这是生命的源泉再没有心的沙漠,再没有爱的荒原死神也望而却步,幸福之花处处开遍啊,只要人人都献出一点爱世界将变成美好的人间韦唯是上世纪809痞女洪晃因一辆林肯怒甩陈凯歌,4婚嫁装修工终获幸福1991年,陈凯歌执导的影片边走边唱在戛纳电影节上拔得头筹,斩获含金量最高的金棕榈奖,这次获奖令他的事业再上新台阶。不过几天之后,陈凯歌的妻子洪晃却单方面宣布两人已经离婚,该消息一真诚才会幸福从天桥经过,买了一束水竹,8根,16元。3支是红色的页子,其他都是绿色的页子,非常漂亮,放在吧台上整个房间就漂亮很多了。水竹主要是好养,加水就可以了,卖花的说,高楼可以养一年的样子伊能静46岁时再婚,47岁的高龄产女,如今的她幸福感爆棚冻龄女神伊能静相信很多人都知道她,她之前参加了乘风破浪的姐姐,凭借优秀的能力她最后杀进总决赛,在这么多位美丽的姐姐中,伊能静看上去非常的美丽,50多岁的她看上去跟30岁的姐姐门年纪深度年利润20亿?永泰能源望煤止渴记者陈慧东编辑时隔三年后,位于陕西榆林的一块富矿终于落定于民营煤炭巨头永泰能源(600157。SH)之手。对于这块煤田,永泰能源给出了一份年营收50亿元净利润20亿元的预期成绩单。靠女人上位的凤凰男,李光洁为何转身娶了小12岁的娇妻?文话多多娱乐圈如同一个光怪陆离的万花筒,什么新闻都有,但是听说过被小三的,被潜规则的,听说过被自杀的吗?李光洁还真遇到过,而且给出的理由还挺充分,为情所困,李光洁一脸无奈地回应这个
5人进8强,冠军却旁落,赵心童格局太小,布雷切尔捡漏夺第3冠万众瞩目的斯诺克冠军联赛落幕,最终的冠军被90后名将布雷切尔夺得。看了直播的球迷都知道,斯诺克首站冠军联赛中国斯诺克球员表现很强势,打到8强中国斯诺克球员占据5强,最后两个小组争夺姆巴佩梦想再夺世界杯!四大队友恐成拦路虎,法国队卫冕前景堪忧当博格巴出现重伤情况时,最郁闷的除了尤文图斯之外,还有法国队,毕竟作为中场核心,博格巴是法国队卫冕的关键人物。虽然说法国队人才济济,但博格巴的作用是无可取代的,现在博格巴还没确定治8月1日起,中国桃花源面向全国人民实行门票免费政策7月29日,记者从桃花源景区了解到,从8月1日开始,常德桃花源景区推出重磅福利中国桃花源面向全国人民实行门票免费政策。优惠时间为2022年8月1日起至9月30日。优惠政策1。202错怪杜锋了!阿不都沙拉木亲口摊牌,无缘中国男篮原因首次曝光北京时间7月29日,中国男篮全队已经正式抵达西班牙开始组织集训拉练,接下来将会在西班牙和法国进行集训一个月的时间,并且期间还会跟不同对手交战四场热身赛,为8月底的世预赛提前做储备,盘点无缘卡塔尔世界杯的球星作为4年一度的国际赛事,作为足球国家队层面的最高荣誉,世界杯的舞台虽然广阔,但是他的承载能力还是有限的。所以几乎每届世界杯都有一些大牌球星被拒之门外,这些球星能力超强,在各大俱乐部用一个暑假,能走遍中国全部34省区?暑假到了,身边好多家长已经开始计划带孩子去旅游了,可是酷热高温人流高峰,也难免让人踌躇这时,是否想过,可以让孩子们利用假期,通过一部书来一次走遍全国的纸上旅行?这套书,就是有中国少28岁辞职去旅行,走遍14个中国也没找到人生的意义有一天,我忘记看到了什么,突然让我对拉萨有了向往。然后我就发了一条朋友圈,说如果点赞的人够多的话我就去西藏。不一会儿,就收获了超多的赞,我当下就买了前往西藏的车票。辞职待业半年之后还停留在4G?vivo低头沉默,有的品牌却打破上限近日,vivo发布了vivoT1x的海外版,这个版本的手机配备了一块支持90Hz刷新率的6。58英寸LCD显示屏,内置骁龙系统680芯片5000万像素后摄和5000毫安电池,4G版好久不见系列来袭!国乒公布名单22人出征捷克,顶尖球员集体缺席随着八月份第一站WTT突尼斯常规挑战赛名单公布后,八月份第二站比赛(除去青少年赛)的名单也紧跟着出炉,国乒大名单已经公布,22名年轻队员们将出征捷克参加WTT支线赛奥洛穆茨站。徐海苹果iPod停产后,以前很火的MP3品牌怎么样了?05后这什么东西很多人都说,苹果iPod停产意味着MP3时代终结。MP3,现在听起来很遥远的一个词,但在诺基亚时代,它曾是年轻人必备的随身设备。谁能想到,曾经火到人手一个MP3会成为,05后看了都据报道,克莱汤普森正在约会前湖人球员的女朋友金州勇士在赢得2022年NBA总冠军之后,金州勇士的不少球员在休赛季后,也是进入了自己愉快的假期,德雷蒙德格林和斯蒂芬库里在各种节目中露脸,对外表示金州勇士是如何出色和伟大。但是对