一直以来,大量做各类管理系统的程序员,大量的时间都在处理各类增删改查问题,对于其他的方面尤其是算法层面的涉及较少,这次就遇到一个问题。
业务场景
用户上传一份Excel,让用户选择其中的部分列头,程序对列头做两两组合,并对所有的组合取Excel表中的数据,绘制一个折线图。
问题分解
- 文件上传。前端使用异步插件提交文件,后台使用file接受即可。升级点在于进度条、重传、备份等
- 文件解析,基于POI、easyexcel等框架,都不难实现
- 选择列头做两两组合,典型的求组合问题,DFS的方式是通用实现方式。
- 组合获取数据,哈希表做key的方式,取出部分列,没难度
- 绘制图表,echarts、d3js、highcharts、G2 都没有太大难度
技术实现
抽象后的背景:针对两两组合,即在m列中求出所有2个的组合,可以通过双重循环完成,简单易懂。
双重循环
for(int i=0;i<arr.length;i++){
for(int j=i+1;j<arr.length;j++){
//...do something
arr[i]; arr[j];
}
}
通用做法,基于dfs算法实现
DFS深度便利
private void dfs(int[] arr, int target,int begin, Deque<Integer> path, Set<List<Integer>> res) {
if ( path.size()== target) {
res.add(new ArrayList<>(path));
return;
}else if(begin>arr.length){
return;
}
for (int i = begin; i < arr.length; i++) {
path.add(arr[i]);
dfs(arr,target,i+1,path,res);
path.removeLast();
}
}
优劣比较
方式一快速简单,上手快,缺点是没有扩展性,一旦组合数变成3、4、5,多重循环显然不合适。
方式二通用能适用各种组合数变化,只要调整target的数字即可。
后记
这是一个并不复杂的问题,但反映出算法在编码过程中的一些问题,一定要注意抽象,将个性化的业务问题抽象为技术问题,用通用的技术去解决,代码的健壮性大大提高。