上个星期,我碰到了一个非常头疼的问题,因为我需要找出两个List集合中的[交集的补集],也就是说,找出他们中互相都不拥有的元素,这个问题看起来似乎很简单。但是做起来其实不然,我在网上搜了很多资料,有用各种各样的方法解决的。可是我也在想,这个问题真的有那么难么,那么今天我就来讲一下,我是如何解决这个问题的 —— 如何找出两个List集合中的交集的补集?我 相信把这个问题解决了,交集,补集,并集什么的....都不是问题了!
前期思路
首先,我们得来准备连个List集合的对象,list1和list2假设他们里面的数据是String类型的(这个方法不仅适合于String类型的数据,还可以是其他类型,这里就以String类型为栗子了)。
其次,我们来个它们分别添加一些数据,为了简单易懂,我就添加一些比较简单的类型的数据了,list一中的数据为:"小王","老王","隔壁老王","老湿机";list2中的数据为:"小王","老王","隔壁老王","老司机"。
最后,按照这个数据来的话,我们的任务就是把两个“司机”给它揪出来,因为list1中没有"老司机",list2中没有"老湿机"。
ok,任务拿到。那么这不就是equals的精妙使用吗。一个个比呗,首先我们用list1中的"小王"来和list2中的所有元素进行equals对比,如果相等了,那接下来怎么办呢。肯定不能直接把它remove掉。那就break这个循环,不用理会它了,因为我们的目标不是他。"老王"和"隔壁老王"也一样,最后来到"老湿机"这个位置,咦,他居然没有找到一个与自己相同的人,那么我们就得把他拿出来单独放起来了,那这个时候,我们就得准备一个临时的List集合把他装起来了。好了,思路很清晰,我们先来把第一阶段的想法实施一下。
第一阶段代码实现
packagecom.asen.container;
importjava.util.ArrayList;
importjava.util.List;
publicclassListDemo{
//新建一个方法disnitersection,便于后续的使用
publicListdisnitersection(Listl1,Listl2){
Listtemplist=newArrayList<>();// 首先准备一个tempList来存放找出来的数据,便于返回
//让list1中的每个元素去和list2中的每个元素做对比,如果不相同就把他加入到临时的集合中,最后返回
for(Strings1:l1){
for(Strings2:l2){
if(s1.equals(s2)){
break;//如果相同则直接寻找下一个
}else{
templist.add(s1);//将不同的元素加入临时templist中
}
}
}
returntemplist;
}
publicstaticvoidmain(String[]args){
ListDemold=newListDemo();//创建对象
Listl1=newArrayList<>();//创建需要对比的list1
Listl2=newArrayList<>();//创建需要对比的list2
//像list1中添加数据
l1.add("小王");
l1.add("老王");
l1.add("隔壁老王");
l1.add("老湿机");
//像list2中添加数据
l2.add("小王");
l2.add("老王");
l2.add("隔壁老王");
l2.add("老司机");
//调用disnitersection方法对比
Listlist=ld.disnitersection(l1,l2);
for(Strings:list){
System.out.println(s);//输出不同结果
}
}
}
如果按照前面的思路走,那我们接下来输出的结果应该是"老湿机",因为每个list1中的元素和list2中的每个元素进行对比,那输出的肯定只有list1中我们想要的那个元素。我们先作但方面的测试。结果:“老湿机”...... 但是,真正的结果却是这样的: 输出结果:老王,隔壁老王,隔壁老王,老湿机,老湿机,老湿机,老湿机 可以看到,这个结果是完全出乎我们的意料啊。不过仔细观察可以发现其中的问题,当list1第一个元素“小王”去和list2中的元素对比的时候,碰巧list2中的第一个元素“也是小王”,所以直接break掉,完全没问题,但是当list1中的第二个元素“老王”来和list2中的元素对比,原来他也是从第一个开始对比着走,结果发现第一个元素“小王”就和自己不一样,所以他就这样被保存到了临时templist中了,这就是问题的所在,后面的也是一样,“老湿机”来对比了list2中的四个元素,结果没有发现一个和自己一样的,所以他就这样被保存了四遍。 那么现在的问题同样也很清晰了,就是说,我们需要在对比不同的情况下,不要立即打断对比并将其加入到templist中,因为就算前面的都不一样,但是最后一个是一样的,这样的情况也需要考虑进去。
中期问题
虽然问题是很明确了,但是我们要怎么去解决这个问题呢?在不同的情况下,继续对比,直到找到相同的才能结束,或者找完全部也没有找到后被加进templist。就是这个地方,让我绞尽脑汁,连洗澡都在想,这个问题怎么解决,最后我实在没办法了,所以拿出笔拿出纸,开始画,因为画图总会给我们带来新的思路。果不其然,有重大发现!!!
我画图后发现,就拿list1的最后一个元素“老湿机”来举栗子,当他把list2中的所有元素都找完后都没有发现和自己一样的元素,那么我们就有了一个解题的线索:因为只要是交集的补集都不会再对方那里找到和自己一样的元素,所以他们都会找遍对方所有的元素后发现没有和自己一样的元素,这就说明,他们找的次数和对方的元素个数是相同的,换句话说,当他们对比的次数和对方的元素个数一样多的时候,那就已经可以说明,它肯定就是我们要找的那个元素了。那么接下来的问题就简单了,我们用代码来实践一下我们的想法:
//新建一个方法disnitersection,便于后续的使用
publicListdisnitersection(Listl1,Listl2){
// 首先准备一个tempList来存放找出来的数据,便于返回
Listtemplist=newArrayList<>();
intcount=0;//记录对比的次数
//让list1中的每个元素去和list2中的每个元素做对比,如果不相同就把他加入到临时的集合中,最后返回
for(Strings1:l1){
for(Strings2:l2){
if(s1.equals(s2)){
//此时count同样需要清零
count=0;
break;
}else{
//否则就说明没有找到相同的,将寻找的次数记下来
count++;
}
if(count==l2.size()){
//当发现对比的次数等于list2的长度(或者大小)时,则说明这是我们需要找的元素
templist.add(s1);
count=0;
}
}
}
returntemplist;
}
当我们在之前代码的基础上把方法里的条件加上我们的判断条件之后,惊奇的发现,输出结果果然是“老湿机”,对了,就是这样的,这样就可以找出两个List集合中的“交集的补集”了,当然以上的代码是单方面的,另一方面把中间的两个for循环调换一遍在放到下面,就可以得到我们想要的结果了。
packagecom.asen.container;
importjava.util.ArrayList;
importjava.util.List;
/**
* @author Asen
*
*/
publicclassTest{
publicstaticListdisnitersection(Listl1,Listl2){
Listlist=newArrayList<>();// 存储需要返回的List
intcount=0;// 记录对比的次数
if(l1.equals(l2)){
list.add("null");
}else{
// 把第一个List中的每个元素和第二个List中的每个元素中对比
for(Stringmax:l2){
for(Stringmin:l1){
if(max.compareTo(min)==0){// 当发现两个List中有同样的元素时,则就直接清零count,并继续寻找下一个元素
count=0;
break;
}else{// 当第一个中的一个元素与第二个中对比
count++;
}
if(count==l1.size()){
list.add(max);
count=0;
}
}
}
for(Stringmax:l1){
for(Stringmin:l2){
if(max.compareTo(min)==0){// 当发现两个List中有同样的元素时,则就直接清零count,并继续寻找下一个元素
count=0;
break;
}else{// 当第一个中的一个元素与第二个中对比
count++;
}
if(count==l2.size()){
list.add(max);
count=0;
}
}
}
}
returnlist;
}
publicstaticvoidmain(String[]args){
Listl1=newArrayList<>();
Listl2=newArrayList<>();
l1.add("小王");
l1.add("老王");
l1.add("隔壁老王");
l1.add("老湿机");
l2.add("小王");
l2.add("老王");
l2.add("隔壁老王");
l2.add("老司机");
l2.add("我是不一样的!!!");
l2.add("我也是不一样的,咯咯咯!!!");
Listtest=Test.disnitersection(l1,l2);
for(StringString:test){
System.out.println(String);
}
}
}
在考虑进去两个集合完全完全相等等情况下,我们的完整代码就是以上那个样子了。个人觉得这个方法简单很多,但是同时也有很多不足之处,比如说当泛型里面是一下不支持equals和CompareTo等方法的时候还需要自己去改,去修正。
PS:以共享IT资源,畅游IT为核心组成的海贼团,每周不定期推送更新完整的项目文章详解,欢迎加入IT海贼船!
黑胡子:“人的梦想,永远不会结束!”