在联机分析处理(OLAP)系统中,需要对存储在数据库或数据仓库中的数据提供分析。由于数据维数不定,无法采用多重for循环进行数据遍历。我在开发过程中一般使用扁平化下标对多维数据进行遍历,今天尝试了一下递归方式,效率更高一些,但是对栈的消耗也更多一些。下面的代码示例使用两种不同的方式对多维数据进行遍历:
- 递归
- 采用扁平化下标
示例代码
package com.yqu.collection;
import java.util.ArrayList;
import java.util.List;
public class MultipleDimensionTraveling <T>{
private List<List<T>> mdList;
public MultipleDimensionTraveling(){
mdList = new ArrayList<List<T>>();
}
public MultipleDimensionTraveling(List<List<T>> mdList){
this.mdList = mdList;
}
public void addDimension(List<T> dim){
mdList.add(dim);
}
public void travelByRecursion(){
if(!mdList.isEmpty())
travelByRecursion(0, new ArrayList<T>(mdList.size()));
}
private void travelByRecursion(int dimIdx, List<T> crossing){
for(int i=0;i<mdList.get(dimIdx).size();i++){
if(crossing.size()<mdList.size())
crossing.add(dimIdx, mdList.get(dimIdx).get(i));
else
crossing.set(dimIdx, mdList.get(dimIdx).get(i));
if(dimIdx==mdList.size()-1){
System.out.println(crossing.toString());
} else {
travelByRecursion(dimIdx+1, crossing);
}
}
}
public void travelByFlatIndice(){
if(!mdList.isEmpty()){
int crossingNum = 1;
int[] cardinalities = new int[mdList.size()];
int[] multipliers = new int[mdList.size()];
for(int i=0;i<mdList.size();i++) {
List<T> dim = mdList.get(i);
cardinalities[i] = dim.size();
crossingNum *= cardinalities[i];
}
for(int i=cardinalities.length-1;i>=0;i--) {
multipliers[i] = (i == multipliers.length - 1)?
1 : cardinalities[i+1]*multipliers[i+1];
}
for(int flatIndice=0;flatIndice<crossingNum;flatIndice++){
handleCrossing(flatIndice, multipliers);
}
}
}
private void handleCrossing(int flatIndice, int[] multipliers){
List<T> crossing = new ArrayList<T>(multipliers.length);
for (int dimIdx = 0; dimIdx < multipliers.length; dimIdx++){
int mbrIdx = flatIndice / multipliers[dimIdx];
crossing.add(dimIdx, mdList.get(dimIdx).get(mbrIdx));
flatIndice = flatIndice % multipliers[dimIdx];
}
System.out.println(crossing);
}
public static void main(String[] args) {
MultipleDimensionTraveling<String> mdlObj =
new MultipleDimensionTraveling<String>();
List<String> dim = new ArrayList<String>();
dim.add("dim1A");
dim.add("dim1B");
dim.add("dim1C");
mdlObj.addDimension(dim);
dim = new ArrayList<String>();
dim.add("dim2A");
dim.add("dim2B");
dim.add("dim2C");
dim.add("dim2D");
mdlObj.addDimension(dim);
dim = new ArrayList<String>();
dim.add("dim3A");
dim.add("dim3B");
mdlObj.addDimension(dim);
System.out.println("Travling by flat indice:");
mdlObj.travelByFlatIndice();
System.out.println("Travling by recursion:");
mdlObj.travelByRecursion();
}
}
运行结果
Multiple dimension list travling by flat indice:
[dim1A, dim2A, dim3A]
[dim1A, dim2A, dim3B]
[dim1A, dim2B, dim3A]
[dim1A, dim2B, dim3B]
[dim1A, dim2C, dim3A]
[dim1A, dim2C, dim3B]
[dim1A, dim2D, dim3A]
[dim1A, dim2D, dim3B]
[dim1B, dim2A, dim3A]
[dim1B, dim2A, dim3B]
[dim1B, dim2B, dim3A]
[dim1B, dim2B, dim3B]
[dim1B, dim2C, dim3A]
[dim1B, dim2C, dim3B]
[dim1B, dim2D, dim3A]
[dim1B, dim2D, dim3B]
[dim1C, dim2A, dim3A]
[dim1C, dim2A, dim3B]
[dim1C, dim2B, dim3A]
[dim1C, dim2B, dim3B]
[dim1C, dim2C, dim3A]
[dim1C, dim2C, dim3B]
[dim1C, dim2D, dim3A]
[dim1C, dim2D, dim3B]
Multiple dimension list travling by recursion:
[dim1A, dim2A, dim3A]
[dim1A, dim2A, dim3B]
[dim1A, dim2B, dim3A]
[dim1A, dim2B, dim3B]
[dim1A, dim2C, dim3A]
[dim1A, dim2C, dim3B]
[dim1A, dim2D, dim3A]
[dim1A, dim2D, dim3B]
[dim1B, dim2A, dim3A]
[dim1B, dim2A, dim3B]
[dim1B, dim2B, dim3A]
[dim1B, dim2B, dim3B]
[dim1B, dim2C, dim3A]
[dim1B, dim2C, dim3B]
[dim1B, dim2D, dim3A]
[dim1B, dim2D, dim3B]
[dim1C, dim2A, dim3A]
[dim1C, dim2A, dim3B]
[dim1C, dim2B, dim3A]
[dim1C, dim2B, dim3B]
[dim1C, dim2C, dim3A]
[dim1C, dim2C, dim3B]
[dim1C, dim2D, dim3A]
[dim1C, dim2D, dim3B]