使用小算法
这个算法主要是用来处理两个数据集合的数据匹配问题。
比如有两个集合:
public class test01 {
public static void main(String[] args) {
// 老公组
List<Couple> husbands = new ArrayList<>();
husbands.add(new Couple(1, "梁山伯"));
husbands.add(new Couple(2, "牛郎"));
husbands.add(new Couple(3, "干将"));
husbands.add(new Couple(4, "工藤新一"));
husbands.add(new Couple(5, "罗密欧"));
// 老婆组
List<Couple> wives = new ArrayList<>();
wives.add(new Couple(1, "祝英台"));
wives.add(new Couple(2, "织女"));
wives.add(new Couple(3, "莫邪"));
wives.add(new Couple(4, "毛利兰"));
wives.add(new Couple(5, "朱丽叶"));
}
}
实体类:
public class Couple {
private Integer familyId;
private String userName;
public Couple(Integer familyId, String userName) {
this.familyId = familyId;
this.userName = userName;
}
public Integer getFamilyId() {
return familyId;
}
public void setFamilyId(Integer familyId) {
this.familyId = familyId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
现在有一个需求:
需要输出的格式为:
梁山伯爱祝英台
牛郎爱织女
干将爱莫邪
工藤新一爱毛利兰
罗密欧爱朱丽叶
第一种方法
直接循环
int count=0;
for (Couple h :husbands){
for (Couple w :wives){
count++;
if (h.getFamilyId().equals(w.getFamilyId())){
System.out.println(h.getUserName()+"爱"+w.getUserName());
}
}
}
这样数据的结果是
梁山伯爱祝英台
牛郎爱织女
干将爱莫邪
工藤新一爱毛利兰
罗密欧爱朱丽叶
25
第二种方法
一个丈夫只匹配到一个妻子,如果匹配到之后,就没有必要再去循环妻子们了
for (Couple h :husbands){
for (Couple w :wives){
count++;
if (h.getFamilyId().equals(w.getFamilyId())){
System.out.println(h.getUserName()+"爱"+w.getUserName());
//如果丈夫匹配到妻子,就结束循环,换丈夫找妻子
break;
}
}
}
梁山伯爱祝英台
牛郎爱织女
干将爱莫邪
工藤新一爱毛利兰
罗密欧爱朱丽叶
15
第三种方法
第一个丈夫匹配到妻子后,第二个丈夫还是会和匹配了丈夫的妻子进行比较,所以需要把匹配到的妻子删除掉
for (Couple h :husbands){
for (Couple w :wives){
count++;
if (h.getFamilyId().equals(w.getFamilyId())){
System.out.println(h.getUserName()+"爱"+w.getUserName());
wives.remove(w);
//如果丈夫匹配到妻子,就结束循环,换丈夫找妻子
break;//如果这里不用break,会报错的
}
}
}
梁山伯爱祝英台
牛郎爱织女
干将爱莫邪
工藤新一爱毛利兰
罗密欧爱朱丽叶
5
第四种方法
终极方法,如果给每一个女嘉宾发一个牌子,这样男嘉宾可以根据牌子直接找到女嘉宾
//给女嘉宾发牌子
Map<Integer, Couple> map = new HashMap<>();
for (Couple w :wives){
map.put(w.getFamilyId(),w);
count++;
}
//男嘉宾上场
for (Couple h :husbands){
Couple couple = map.get(h.getFamilyId());
System.out.println(h.getUserName()+"爱"+couple.getUserName());
count++;
}
梁山伯爱祝英台
牛郎爱织女
干将爱莫邪
工藤新一爱毛利兰
罗密欧爱朱丽叶
10
问题:
上述第三种方法,删除集合元素会有问题,如果不用break的话,会ConcurrentModificationException(并发修改异常),因为增强for循环的底层是迭代器,迭代器的next()方法会检查并发修改异常(集合中的‘版本号’是否在遍历的过程中发生改变),对集合的元素进行增删的时候,会修改版本号。
而对于list,有两个遍历方式:
1.增强for循环(迭代器)
2.普通for循环,集合遍历元素
但是两者不能混用,第三种方法,就是混用了,所以会报异常
解决方法:
一.用迭代器遍历元素,用迭代器删除元素
//获取女嘉宾的迭代器
Iterator<Couple> iterator = wives.iterator();
for (Couple h :husbands){
//遍历迭代器
while (iterator.hasNext()){
if (h.getFamilyId().equals(iterator.next().getFamilyId())){
System.out.println(h.getUserName()+"爱"+iterator.next().getUserName());
//删除元素
iterator.remove();
}
}
}
二.用普通for循环进行遍历集合,删除集合
for (Couple h :husbands){
for (int i=0;i<wives.size();i++){
if (h.getFamilyId().equals(wives.get(i).getFamilyId())){
System.out.println(h.getUserName()+"爱"+wives.get(i).getUserName());
wives.remove(i);
i--;//集合里元素减少了一个
count++;
}
}
}
ps:内容来源于 bravo1988 大神