两个List集合求交集想必学过Java的都知道用系统自带的retainAll()方法,但是在数据量比较大时,这个方法效率并不高,利用空余时间研究了几种数据量较大时求两个集合交集的办法。本文主要研究了JDK自带方法求交集、Guava集合求交集、Java8的parallelStream并行流求交集、双指针方法求交集以及bitmap求交集的方法和效率。

JDK自带方法

最常用的求交集方法,在小数据量的时候没什么问题,一旦两个集合的数据量达到几十万级别时,效率就严重偏低,底层实际上也是两个for循环加一个contains判断,只不过JDK做了一些相应优化,不是单纯O(n^2)的双重for循环,感兴趣的同学可以阅读相应源码。

Guava集合工具类

Guava是谷歌出的一个工具类,里面包含了很多实用的方法,求交集的方法为Sets.intersection(list, list2)实际测试下来相当高效。

Java8并行流

parallelStream()借用了Java7的Fork/Join框架,采用分治+多线程的思想来求交集

双指针法

双指针法又称拉链法,就是先将两个集合排序,然后借用了二路归并排序的思想,利用两个指针分别在两个集合里面做标记,比较大小然后滑动,最后得到结果。

BitMap方法

将数据存进两个bitMap中,然后进行与操作,得到最终结果,属于一种空间换时间的方法,BitMap思想在海量数据处理中有很多妙用。

下面贴上具体实现的代码:

package com.test.spring.learn.retainall;

import com.google.common.collect.Sets;

import org.apache.commons.lang3.StringUtils;

import java.io.*;

import java.util.*;

import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;

/**

* Created by GeekBoy on 2020/1/4.

*/

public class RetainAllTest {

public static void main(String[] args) {

retainAllByGuava();

retainAllByBitSet();

retainAllByTwoPoint();

retainAllByStream();

retainAllByJDK();

}

/**

* 用JDK方法求交集

*/

private static void retainAllByJDK() {

List txtList = getIntegerList("e:\\a.txt");

List txtList2 = getIntegerList("e:\\b.txt");

long begin = System.currentTimeMillis();

txtList.retainAll(txtList2);

long end = System.currentTimeMillis();

System.out.println("JDK方法耗时:" + (end - begin));

System.out.println("交集的个数为:" + txtList.size());

}

/**

* 利用guava集合求交集

*/

private static void retainAllByGuava() {

List txtList = getIntegerList("e:\\a.txt");

List txtList2 = getIntegerList("e:\\b.txt");

long begin = System.currentTimeMillis();

Set list = new HashSet<>(txtList);

Set list2 = new HashSet<>(txtList2);

Sets.SetView intersection = Sets.intersection(list, list2);

long end = System.currentTimeMillis();

System.out.println("guava方法耗时:" + (end - begin));

System.out.println("交集的个数为:" + intersection.size());

}

/**

* java8 stream流求交集,实质上底层是用的多线程fork/join框架

*/

private static void retainAllByStream() {

List txtList = getIntegerList("e:\\a.txt");

List txtList2 = getIntegerList("e:\\b.txt");

long begin = System.currentTimeMillis();

long count = txtList.parallelStream().

filter(item -> txtList2.contains(item)).count();

long end = System.currentTimeMillis();

System.out.println("stream流求交集方法耗时:" + (end - begin));

System.out.println("交集的个数为:" + count);

}

/**

* 双指针法求两个list的交集

*/

private static void retainAllByTwoPoint() {

List txtList = getIntegerList("e:\\a.txt");

List txtList2 = getIntegerList("e:\\b.txt");

long begin = System.currentTimeMillis();

Collections.sort(txtList);

Collections.sort(txtList2);

int count = 0;

int m = 0;

int n = 0;

int length = txtList.size() + txtList2.size();

for (int i = 0; i < length; i++) {

if (m < txtList.size() && n < txtList2.size()) {

if (txtList.get(m).equals(txtList2.get(n))) {

count++;

m++;

n++;

} else if (txtList.get(m).compareTo(txtList2.get(n)) > 0) {

n++;

} else {

m++;

}

} else if (m < txtList.size()) {

if (txtList.get(m).equals(txtList2.get(n - 1))) {

count++;

}

m++;

} else if (n < txtList2.size()) {

if (txtList.get(m - 1).equals(txtList2.get(n))) {

count++;

}

n++;

}

}

long end = System.currentTimeMillis();

System.out.println("双指针方法耗时:" + (end - begin));

System.out.println("交集的个数为:" + count);

}

/**

* 利用bitmap求两个list的交集

*/

private static void retainAllByBitSet() {

List txtList = getIntegerList("e:\\a.txt");

List txtList2 = getIntegerList("e:\\b.txt");

long begin = System.currentTimeMillis();

BitSet bitSet = new BitSet(Collections.max(txtList));

BitSet bitSet1 = new BitSet(Collections.max(txtList2));

for (int i = 0; i < txtList.size(); i++) {

bitSet.set(txtList.get(i));

}

for (int i = 0; i < txtList2.size(); i++) {

bitSet1.set(txtList2.get(i));

}

bitSet.and(bitSet1);

long end = System.currentTimeMillis();

System.out.println("bitSet方法耗时:" + (end - begin));

System.out.println("交集的个数为:" + bitSet.cardinality());

}

/**

* 从文件读取两个list

*

* @param filePath

* @return

*/

private static List getIntegerList(String filePath) {

InputStream inputStream = null;

InputStreamReader is = null;

BufferedReader br = null;

Set txtList = new HashSet<>();

try {

File txtFile = new File(filePath);

if (txtFile.exists()) {

inputStream = new FileInputStream(txtFile);

is = new InputStreamReader(inputStream, "UTF-8");

br = new BufferedReader(is);

String str = null;

while ((str = br.readLine()) != null) {

if (StringUtils.isNotBlank(str)) {

txtList.add(Integer.valueOf(str));

}

}

}

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if (inputStream != null) {

inputStream.close();

}

if (is != null) {

is.close();

}

if (br != null) {

br.close();

}

} catch (Exception e) {

e.printStackTrace();

}

}

return new ArrayList<>(txtList);

}

}

最终的运行结果如下,只运行了一次,结果并不严谨,仅供参考:

guava方法耗时:33

交集的个数为:151695

bitSet方法耗时:25

交集的个数为:151695

双指针方法耗时:63

交集的个数为:151695

stream流求交集方法耗时:28240

交集的个数为:151695

JDK方法耗时:91838

交集的个数为:151695

从上面的结果可以看出bieSet是最快的,guava的方法其次,JDK自带的最慢。平时使用如果数据量不是太大用guava的工具类即可,不得不说谷歌的算法还是相当厉害的。

参考链接

镜像地址

java 交集_Java大集合求交集的方法比较相关推荐

  1. JAVA——两个List集合求交集、并集和差集(去重)模板

    关注微信公众号:CodingTechWork,一起学习进步. 引言   经常遇到一些集合类之间的过滤数据.求合集之类的问题,在此以List为例,毕竟在数据库中取数据后,我们使用比较多的是List集合进 ...

  2. Java 数组转成集合List三种方法和(数组、集合List、Set相互转换)

    Java 数组转成集合List 三种方法 package com.list;import java.util.ArrayList; import java.util.Arrays; import ja ...

  3. Java中遍历Set集合的三种方法

    Map集合:链接: Map集合的五种遍历方式及Treemap方法 Set集合:链接: Java中遍历Set集合的三种方法 TreeSet集合:链接: Java深入了解TreeSet,和迭代器遍历方法 ...

  4. Java中遍历Set集合的三种方法(实例代码)

    哈喽,欢迎来到小朱课堂,下面开始你的学习吧! Java中遍历Set集合的三种方法 废话不多说,直接上代码 1.迭代遍历: Set set = new HashSet(); Iterator it = ...

  5. 大数据集合求交集_Java8 实现ArrayList求交集并集差集

    本文借助Java8的Stream API完成ArrayList集合运算:求交集.并集和差集! public class CollectionUtil {/*** 判断为空*/public static ...

  6. 大数据集合求交集_还记得学生时代数学老师教的“集合”吗?

    犹记得老师敲着黑板,强调"集合"的特性:无序.不重复,没想到多年后在咱们编程中派上了用场. 集合 # 数据分析中,经常需要把字符串.列表中的数据去重,怎么办呢?用"集合& ...

  7. 【分享】Java集合求交集、并集、差集

    面试场景: 之前遇到一个长得很有趣的面试官问两个集合怎么求他们的交集.并集.茶集,回答之后觉得非常有意思,在这里记录一下: 概念说明 一.交集 交集:两个集合的公共(相交)部分,如下图: 代码案例: ...

  8. java 区间并集,Java中多个集合的交集,并集和差集

    一.交集 java中交集使用 A.retainAll(B) ,交集的结果在集合A中. import org.junit.Test; import java.util.HashSet; import j ...

  9. Java把一个大集合拆分成多个小集合,可以利用多线程提升并发处理效率

    场景: 在开发中,如果一个集合中的数据量特别大,那么对这个集合进行循环处理业务可能就会比较耗时,为了提升效率,可以考虑把大集合拆分成多个小集合,然后用多线程对拆分后的多个小集合进行处理 拆分: 1.拆 ...

最新文章

  1. 近期活动盘点:大数据应用中日交流论坛、几位专家带你认识Flink、青年自强AI计划 CV免费公开课!(11.12-11.23)...
  2. 中心化,去中心化?关乎互联网未来命运的重要选
  3. VC两个线程协作运行,轮流运行的
  4. python软件下载安装要钱吗-PyCharm下载和安装详细步骤
  5. html导航去下划线,纯CSS实现导航栏下划线跟随的示例代码
  6. mac11.5.2版本虚拟机SeaBIOS不引导,kvm虚拟机状态为pause
  7. 震惊kafka_5个令人震惊的统计数据证明日志不足
  8. stm32程序怎么设置apb2总线时钟_stm32学习笔记
  9. MySQL常用数据类型
  10. computed用发_Vue中的computed属性和nextTick方法
  11. 运行maven项目整合ssm时的错误笔记
  12. java 类的继承 例题_Java_接口与类之间继承例题
  13. 部分免费开放的电子图书馆
  14. 合肥工业大学C语言提交作业,合肥工业大学C语言题库程序设计.doc
  15. 知云文献翻译打不开_沙拉查词—— 划线翻译的一股清流
  16. 20、CSS中单位:【px和%】【em和rem】【vw|vh|vmin|vmax】的区别
  17. ARM到底是冯诺依曼结构还是哈佛结构?
  18. 探索学习:网红容器引擎Docker
  19. 使用Python将TXT文本内容读取后生成指定XML格式的文件
  20. 波特率,kbps,Mbps含义

热门文章

  1. MFC主流开发库BCGControlBar下载安装教程!
  2. 变更管理在软件项目管理中的主要活动
  3. 【WSN定位】基于matlab磷虾群算法求解WSN定位优化问题【含Matlab源码 448期】
  4. 【转】如何成就更优秀的自己
  5. 网络经济与企业管理 章节图
  6. ES中数据流Data streams详解
  7. TXB0104的使用
  8. Linux网络操作系统及应用教程(项目式)项目五
  9. 阿里高层大调整/ 推特突发大规模宕机/ 任天堂砍掉Switch Pro…今日更多新鲜事在此...
  10. html offsetwidth 字符串宽度,scrollWidth、clientWidth、offsetWidth、width的区别