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

大数组元素差异比较下的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 毫秒  #1000WremoveAll耗时分析
  最后,来分析下为什么在大数组元素比较时,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 实现。

尿道炎为淋病范畴,尿道炎的四种症型!尿道炎分为膀胱湿热型肝胆郁热型胃肠湿热型肾阴不足型1。膀胱湿热型膀胱湿热型主要表现发热恶寒尿频尿急尿痛小腹胀痛腰酸苔黄脉濡数治宜清热泻火通淋利水常用药大黄瞿麦萹蓄车前子木通山栀子甘众人对颜丙涛的看法,墨菲逼其退役,小特佛系求情,丁俊晖太冷血北京时间12月15号,日前中国斯诺克七人正陷入赌球风波,丁俊晖近二十年职业生涯维持的正面形象很可能被梁文博和颜丙涛等人毁于一旦,这次丑闻让颜丙涛的职业生涯蒙上一层阴影,年仅22岁的埃因青年VS阿贾青年世界杯已经进入了白热化的阶段,我们也不能错过一些小型的比赛,毕竟有些时候,小型的比赛会比世界杯更多。当然,今天我们要说的,就是荷乙两支超级豪门之间的对决,埃因霍温第二支对阵阿贾克斯20岁小将横空出世!广东队锋线有救了,杜锋终于等到周鹏接班人广东队重返争冠行列第一阶段结束,广东队只排在联盟第11位,觉得这支球队真的到了一个转折点。进入到第二阶段,广东队势不可当,先后战胜北京广州天津辽宁,豪取四连胜,排名已经上升到了第五瓦妮莎守寡失败?与光头男互送飞吻太暧昧,40岁单身富婆太抢手近日有不少球迷关注到了瓦妮莎和她的家人,瓦妮莎在前不久参与了许多活动,与此同时还和自己的大女儿多次拍摄写真,看起来非常的英姿飒爽,颇有女强人的风范,瓦妮莎之所以可以得到广泛关注,最五位基金经理的投资干货!中欧基金年度策略会揭秘如何穿越周期长期制胜?投资唯有拥有全局视野,才能跳出只见树木不见森林的局限,洞察投资优秀企业的本质,把握中国乃至全球经济的发展趋势。即将过去的2022年是市场震荡加剧的一年,并没有出现趋势性机会,300常见的三种补阳中成药,哪个效果更好?如果你平时总是觉得怕冷畏寒穿的厚也不暖和,天一凉就手脚冰凉,晚上睡觉时被窝怎么也暖不热,这多半是你阳虚了。那我们平时常见的桂附地黄丸金匮肾气丸和附子理中丸,哪个补阳效果更好呢?应该小洋人日记第三天我快好了,儿子接上了,全盘端了今天我的症状就是咳嗽,但是咳嗽起来症状类似于普通感冒,嗓子不疼了。其他症状也消失了。但是,还没容我松一口气,昨天晚上我儿子就发烧了。这几天我羊了之后,为了不传染给孩子,我尽量和孩子宝山疾控话健康到了冬天,气温骤降血管极易受到冷空气刺激而收缩造成血液流通受阻血液黏度增高使心脑负荷加重动脉粥样硬化斑块易破裂冠状动脉易痉挛进而诱发心脑血管疾病的发作和复发今天就让我们一起来了解下咳嗽最怕这个汤!随手一煮,清热又润肺,尤其老人小孩要多喝现在正值深冬的季节,气候比较干燥,一到冬季,大家一般会懒于锻炼,抵抗力就容易下降,因此到了冬季总会觉得自己的喉咙发干发痒,偶尔就想咳嗽。如果情况再严重一些的,甚至还会感冒,所以我们什么时候喝水对身体好喝水对身体好的时问有630喝水排毒叉养颜830喝水体贴又健康1100喝水解乏叉放松1250喝水减负又减肥1500喝水提神叉醒脑1730喝水消化又吸收2200喝水可解毒,排泄,消化增
对RNG选手没多大印象!Faker战败采访惹怒LCK网友李哥别丢人了在RNG三比一横扫T1之后,Faker因为这次MSI全程都在35MS延迟下完成,不太适应以及RNG这边没有给我留下深刻印象的选手,我只是觉得输掉了比赛很可惜这两句话的低情商采访,搞原湖南省中小企业信用担保有限责任公司董事长邹志新接受监察调查原湖南省中小企业信用担保有限责任公司董事长邹志新涉嫌严重违法,经湖南省监委指定,目前正接受永州市监委监察调查。邹志新简历邹志新,男,汉族,1968年9月出生,湖南吉首人,1991年有些病是省出来的!提醒3个省钱习惯,可能省出癌细胞俗话说一天省下一两粮,十年要用仓来装。从小到大,我们都被教育要勤俭节约,这是中国人的传统美德,更是刻在父辈身上的一种生活习惯。但我们很难想象,在大都市东京,竟然也有省钱如命的人。一赶快把公积金的钱取出来吧,你知道损失了多少利息吗?公积金账户存款利息高,还是取出来转存到银行利息高?公积金账户的钱如何理财,我在问答中有过多次的解答。公积金账户的钱,到底是放在里面利息高,还是取出来存入银行利息高。首先给你答案肯定释放战俘解除封锁归还领土,法德劝普京服软,乌克兰自绝生路5月28日,据俄罗斯卫星通讯社报道,俄罗斯总统普京当天同法国总统马克龙德国总理朔尔茨通电话,就乌克兰局势交换意见。此次通话时长约80分钟,在通话中,马克龙和朔尔茨要求普京同乌克兰总维也纳数名乌克兰人殴打2名出租车司机,奥地利议员发文滚出我们的国家(观察者网讯)据奥地利OE24电视台29日报道,这两天,数名乌克兰人在奥地利首都维也纳殴打出租车司机的视频在网上引起轰动。而据当地警方称,一名司机当场被殴打至昏迷,颅骨骨折。该事件法媒泽连斯基访问哈尔科夫地区,系俄乌冲突爆发后首次据法新社29日报道,乌克兰总统弗拉基米尔泽连斯基访问了哈尔科夫地区,这是俄乌冲突以来泽连斯基首次访问乌克兰东部地区,近几周来俄罗斯已从哈尔科夫地区撤出。报道称,泽连斯基办公室在电报台对美军购出现新变化美国告诉台军这些武器,不卖了M142高机动火箭炮系统(HIMARS)。中国台湾网5月30日讯拜登政府上台后一方面加大对台军售力度,另一方面调整对台军售策略,意图所谓打造台军不对称战力。台媒也注意到,台湾对美军10年后,再看变形记吴宗宏易虎臣各自的境遇,人生差距一目了然2012年,深圳富家公子哥易虎臣和云南山里娃吴宗宏,同时收到了湖南卫视变形计第五季的邀请函。他们7天的互换生活,引发出巨大争议,也彻底改变了各自人生。13岁的易虎臣一改往期城市主人公务员考试,考上两办和组织部的干部,谁更容易提拔?参加公务员考试,考上两办的公务员或考上组织部的公务员,谁更容易得到优先提拔的机会呢?现在,就让我们来谈谈这个问题。首先,小编想要告诉你的是,在公务员考试中,两办和组织部发布的招考岗8旬老头捡垃圾攒下13万,痴爱少妇送部手机就3万,少妇你太老了文。小芳请问您是李星星吗?湖南临湘市人民医院重症监护室里,一位40多岁戴着眼镜的时尚少妇正在照顾病床上的儿子,听到记者的问话后眼神中掠过一丝惊慌,站起身交代了儿子一句替我保管好手机