Java编程经验---比较两个List对象差异

问题引入

如何比较两个List对象的差异,这个问题来源于我最近正在开发的新系统中的一个细节。大致情况就是,从数据库中的一个视图A向另一个数据库的一张B表进行数据迁移。A的数据会随时更新,为了保证表B也可以及时获取数据,需要采用定时任务,不断同步数据。

每N分钟
视图A
表B

视图A中的数据在导入表B时,可能有数据已经在表B中,重复的导入浪费性能且可能发生潜在错误。那么就需要分析数据的差异后进行导入。先设一个前提,视图A与表B的结构相似,Primary Key为表中的某一单字段。

视图A示例

UserIdUserNameStatus
1MikeOK
2TrumpNO
3LiLiOK

表B示例

UserIdUserNameGender
1MikeMen
2TrumpWomen
5ChouMen

*这里的 UserId 时 Primery Key

解决问题

简化模型

我们可以先将问题简化为两个基本类型的List,举个最简单的例子就是两个List<int>

一般的办法

如何对比两个List的差异,最简单粗暴的当然就是使用两个for循环。

public static void main(String[] args) {
	int i = 0 ;
	//对比ListA和ListB的差异
	List<Integer> ListA = new LinkedList();
	List<Integer> ListB = new LinkedList();
	//获取相同的元素放入ListC
	List<Integer> ListC = new LinkedList();
	
	while( i<10000){
		ListA.add(i);
		i++;
	}
	i = 5;
	while( i<10005){
		ListB.add(i);
		i++;
	}
	
	//程序开始时间
	long st = System.nanoTime();
	//取得相同的元素
	for(int aIndex: ListA)
	{
		for(int bIndex: ListB)
		{
			if(aIndex == bIndex)
			{
				ListC.add(aIndex);
			}
		}
	}
	
	//分辨结束
	System.out.println("total times "+(System.nanoTime()-st));
	
	ListA.removeAll(ListC);
	ListB.removeAll(ListC);
	ListA.addAll(ListB);
	
	System.out.println(ListA.toString()); //打印差异元素
}

结果

total times 362768500
[0, 1, 2, 3, 4, 10000, 10001, 10002, 10003, 10004]

此时的算法复杂度为
O ( m × n ) O(m×n) O(m×n)

速度更快的方法

空间换时间

 public class Test {

	public static void main(String[] args) {
		int i = 0 ;
		//对比ListA和ListB的差异
		List<Integer> ListA = new LinkedList();
		List<Integer> ListB = new LinkedList();
		//获取相同的元素放入ListC
		List<Integer> ListC = new LinkedList();

		while( i<10000){
			ListA.add(i);
			i++;
		}
		i = 5;
		while( i<10005){
			ListB.add(i);
			i++;
		}
		
		Map<Integer,Integer> listMap = new HashMap();
		
		//程序开始时间
		long st = System.nanoTime();
		
		//取得相同的元素
		Iterator<Integer> iteratorA = ListA.iterator();
		while(iteratorA.hasNext())
		{
			Integer tempInteger = iteratorA.next(); 
			listMap.put(tempInteger.intValue(),tempInteger);
		}
		
		Iterator<Integer> iteratorB = ListB.iterator();
		while(iteratorB.hasNext())
		{
			Integer tempInteger = iteratorB.next(); 
			if(listMap.containsKey(tempInteger))
			{
				ListC.add(tempInteger);
			}
		}
		//分辨结束
		System.out.println("total times "+(System.nanoTime()-st));
		
		ListA.removeAll(ListC);
		ListB.removeAll(ListC);
		ListA.addAll(ListB);
		
		System.out.println(ListA.toString()); //打印差异元素
	}
}

结果

total times 2537200
[0, 1, 2, 3, 4, 10000, 10001, 10002, 10003, 10004]

做了一点改善,将原来的For循环用迭代来完成遍历,速度快了20%

此时的算法复杂度为
O ( m + n ) O(m+n) O(m+n)
很明显引入HashMap之后,算法复杂度大幅下降。这是由于在HashMap中查找元素的算法复杂度可以达到恐怖的O(1)。

特别说明
Java 8 之后,HashMap引入了红黑树存储,使得存储效率进一步提升,触发条件就是List长度大于8。

Lambda表达式解决办法

	public static void main(String[] args) {
		int i = 0 ;
		//对比ListA和ListB的差异
		List<Integer> ListA = new ArrayList();
		List<Integer> ListB = new ArrayList();
		//获取相同的元素放入ListC
		List<Integer> ListC = new ArrayList();

		while( i<10000){
			ListA.add(i);
			i++;
		}
		i = 5;
		while( i<10005){
			ListB.add(i);
			i++;
		}
		
		//程序开始时间
		long st = System.nanoTime();
		//取得相同的元素
		//采用Lambda表达式实现
		ListC = ListA.stream().filter(p -> ListB.contains((Integer)p)).collect(Collectors.toList());
		
		//分辨结束
		System.out.println("total times "+(System.nanoTime()-st));
		
		ListA.removeAll(ListC);
		ListB.removeAll(ListC);
		ListA.addAll(ListB);
		
		System.out.println(ListA.toString()); //打印差异元素
	}

先放结果吧

total times 41008300
[0, 1, 2, 3, 4, 10000, 10001, 10002, 10003, 10004]

总的来说还是要比第一种方法要快5,6倍,但是和使用HashMap还是有一定的差距。但是很明显语句非常的简洁。所以适当使用Lambda表达式可以使代码更加优雅。但是处理大量的数据时,效率不佳,不推荐。

结语

点滴积累,才能扎实成长。

时间有限,如有问题,及时更正。

  • 8
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值