java 两个list 交集 并集 差集 去重复并集
需要明白List是引用类型,引用类型采用引用传递。
我们经常会遇到一些需求求集合的交集、差集、并集。例如下面两个集合:
List<String> list1 = new ArrayList<String>();
list1.add("1");
list1.add("2");
List<String> list2 = new ArrayList<String>();
list2.add("2");
list2.add("3");
1.求差集
例如,求List1中有的但是List2中没有的元素:
public static void test3(List list1,List list2){
list1.removeAll(list2);
System.out.println(list1);
}
结果:[1]
查看ArrayList的removeAll的源码
public boolean removeAll (Collection < ? > c){
Object.requireNonNull(c);
return batchRemove(c,false);
}
再查看batchRemove的源码:(如果传的第二个参数是false,保留差集;如果传的是true,保留的是交集)
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;
}
是重新定义elementData数组的元素,下面代码的作用是将本集合中不包含另一个集合的元素重新加入元素,以此实现删除的功能(注意上面调用的方法传的参数是false,也就是不包含的元素得以保留,实现差集的功能)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
2.求并集(不去重)---将一个集合全部加入另一个集合
public static void test(List list1,List list2){
list1.addAll(list2);
System.out.println(list1);
}
结果:[1、2、2、3]
查看ArayList的addAll()源码是数组复制:
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
再查看System的arraycopy发现是一个native方法(本地方法):---其实system类的好多方法都是native方法
public static native void arraycopy(Object src,int srcPos,Object dest,int DestPos,int length);
3、求并集(去重)
例如:求List1和List2的并集,并实现去重。
思路是:先将list中与list2重复的去掉,之后将list2的元素全部添加进去。
public static void test1(List list1, List list2) { list1.removeAll(list2); list1.addAll(list2); System.out.println(list1); }
结果:[1、2、3]
4、求交集
例如:求List1和List2中都有的元素。
public static void test2(List list1, List list2) { list1.retainAll(list2); System.out.println(list1); }
结果:[2]
在上面 1 的实验过程中,我们知道batchRemove(Collection,true)也是求交集,
所以猜想 retainAll 内部应该是调用 batchRemove(Collection,true),查看ArrayList的源码如下:
public boolean retainAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, true); }
原文地址:https://www.cnblogs.com/huang2979127746/p/15009333.html
- C++拷贝构造函数(深拷贝,浅拷贝)
- 安装glog和gflags
- FFmpeg_3.2.4+SDL_2.0.5学习(1)音视频解码帧及显示/播放数据
- FFmpeg_3.2.4+SDL_2.0.5学习(2)视频同步基础
- ubuntu17.04更换主题
- ubuntu17.04新安装之后的软件准备
- 打造一流编辑器vimplus
- ffmpeg+sdl播放类
- 拉丁猪文字游戏
- 在Windows Mobile的控制台应用中使用Notification
- vim使用经验积累
- Spring+Mybatis+Maven+Mysql编程实战
- LD_LIBRARY_PATH和LIBRARY_PATH的区别
- c++11的Condition_variable
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 查看MYSQL表数据大小
- 解决Centos6.0下出现protocol not available错误
- MYSQL删除大数据表经验总结
- 推荐4款堪比Google的搜索网站
- 那些年你走过下划线的坑
- 2018你该认真学Python了
- 服务端口占用案例分析
- 查看Linux系统版本信息记录
- JVM加载TimeZone读取文件优先级实战分析
- MYSQL临时表导致根分区爆满问题分析
- Shell遍历数字递增方法小记
- Elasticsearch UNASSIGNED索引分片问题分析
- 解决Elasticsearch分片未分配的问题「译」
- Linux下netstat命令常用方法推介
- Nginx Unit 1.0发布,可运行Go、Python、PHP等多种语言