【发布时间】:2014-10-07 18:20:31
【问题描述】:
我有一个ArrayList<Map<String, Object>>,其中包含数据库表等数据。我想自己计算 Java 中的成员总数。 GroupBY Rollup/Cube 可以在 SQL 中实现相同的功能。
我写了一个函数来计算 GroupBy Cube。
public static List<Map<String, Object>> applyGroupBy(List<LevelDetail> dimensionColumns, List<MeasureDetail> numericColumns, List<Map<String, Object>> resultset) {
List<Map<String, Object>> resultsetNew = new ArrayList<Map<String, Object>>();
Map<String, List<Double>> grandTotalMap = new HashMap<String, List<Double>>();
for (LevelDetail levelDetail : dimensionColumns) {
Stream<Map<String, Object>> stream = resultset.stream();
stream.collect(Collectors.groupingBy(m -> m.get(levelDetail.getName()), LinkedHashMap::new, Collectors.mapping(m -> m, Collectors.toList()))).forEach((g, r) -> {
Map<String, Object> row = new HashMap<String, Object>();
row.put(levelDetail.getName(), g);
for (MeasureDetail measureDetail : numericColumns) {
DoubleStream valueStream = r.stream().mapToDouble(p -> {
p.put(levelDetail.getName() + "_nb_grouping", 0);
resultsetNew.add(p);
return Double.parseDouble(p.get(measureDetail.getName()) != null ? p.get(measureDetail.getName()).toString() : "0");
});
Double value = getAggregatedResult(valueStream, measureDetail.getMeasure_rollup_expr());
row.put(measureDetail.getName(), value);
if (dimensionColumns.indexOf(levelDetail) == 0) {
if (!grandTotalMap.containsKey(measureDetail.getName())) {
grandTotalMap.put(measureDetail.getName(), new ArrayList<Double>());
}
grandTotalMap.get(measureDetail.getName()).add(value);
}
}
row.put(levelDetail.getName() + "_nb_grouping", 0);
for (LevelDetail ld : dimensionColumns) {
if (!ld.getName().equals(levelDetail.getName())) {
row.put(ld.getName() + "_nb_grouping", 1);
row.put(ld.getName(), null);
}
}
resultsetNew.add(row);
});
}
Map<String, Object> row = new HashMap<String, Object>();
for (LevelDetail levelDetail : dimensionColumns) {
row.put(levelDetail.getName(), null);
row.put(levelDetail.getName() + "_nb_grouping", 1);
}
for (MeasureDetail measureDetail : numericColumns) {
Double value = getAggregatedResult(grandTotalMap.get(measureDetail.getName()).stream().mapToDouble((i) -> (Double) i), measureDetail.getMeasure_rollup_expr());
row.put(measureDetail.getName(), value);
}
resultsetNew.add(row);
resultset = new ArrayList<Map<String, Object>>(new LinkedHashSet<Map<String, Object>>(resultsetNew));
resultsetNew.clear();
resultsetNew.addAll(resultset);
return resultsetNew;
}
private static final String AVG = "avg";
private static final String MIN = "min";
private static final String MAX = "max";
private static Double getAggregatedResult(DoubleStream ds, String agg) {
switch (agg.toLowerCase()) {
case AVG:
return ds.average().getAsDouble();
case MIN:
ds.min().getAsDouble();
case MAX:
ds.max().getAsDouble();
default:
return ds.sum();
}
}
我想编写一个按 Rollup 分组的方法。无论是按 Rollup 还是 Cube 分组,都可以将其参数化为相同的功能。
【问题讨论】:
-
如果 SQL 是您的灵感来源,那么您真的应该考虑通过
GROUPING SETS推广ROLLUP和CUBE。这可能还会简化您的广义算法... -
您在
min和max聚合中缺少return,并且将返回sum。