使用Java 8流和收集器嵌套值

使用Java 8流和收集器嵌套值,java,java-stream,collectors,Java,Java Stream,Collectors,我有以下数据集来表示销售记录: sn| Channel | Category | Brand |qty | gross | 1 |"Mini Market" | "Large MM" | "ARIEL" |3 | 100 | 2 |"Mini Market" | "Large MM" | "ARIEL" |6 | 200| 3 |"Mini Market"

我有以下数据集来表示销售记录:

 sn|    Channel    | Category   | Brand             |qty    |  gross |          
 1 |"Mini Market" | "Large MM" | "ARIEL"            |3      | 100 |
 2 |"Mini Market" | "Large MM" | "ARIEL"            |6      | 200| 
 3 |"Mini Market" | "Large MM" | "GILLETTE"         |12     | 103.88| 
 4 |"Mini Market" | "Large MM" | "OLAY"             |2      | 50  | 
 5 |"Mini Market" | "Large MM" | "OLAY"             |6      | 10| 
 6 |"Mini Market" | "Small MM" | "GILLETTE"         |5      | 20 |
 7 |"Mini Market" | "Small MM" | "GILLETTE"         |3      | 30| 
 8 |"Mini Market" | "Small MM" | "OLAY"             |3      | 80.3  |
 9 |"Mini Market" | "Small MM" | "ORAL B"           |6      | 100 |
 10|"Mini Market" | "Small MM" | "ORAL B"           |7      | 150 |
POJO课程:

class SalesRecord{
    private String channel;
    private String category;
    private String brand;
    private int qty;
    private double gross;

    //getters and setters


}

class PivotTable {
    Map<Integer,Set<String>> uniqueAttirbuteMap;
    List<Pivot> pivot;
    //other fields and methods

}

class Pivot {
    public String attribute;
    Map<String, Double> aggregates;
    List<Pivot> pivotList;
    //other fields and methods

}
我努力实现的目标如下:

SalesCollector collector = new SalesCollector(groups);
        final Map<String, Map<String, Map<String, PivotTable>>> results = salesRecords.stream()
            .collect(groupingBy(SalesRecord::getChannel(), TreeMap::new,
                groupingBy(SalesRecord::getCategoryName(), TreeMap::new,
                    groupingBy(SalesRecord::getBrand(), TreeMap::new, collector))));

List<PivotTable> myList = results.values().stream()
            .map(Map::values)
            .flatMap(Collection::stream)
            .map(Map::values)
            .flatMap(Collection::stream)
            .collect(Collectors.toList());
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Large MM), Pivot(attribute:ARIEL, aggregates:{ sum_qty=9, sum_gross=300 })])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Large MM), Pivot(attribute:GILLETTE, aggregates:{ sum_qty = 12, sum_gross= 103.88})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Large MM), Pivot(attribute:OLAY, aggregates:{ sum_qty = 8, sum_gross= 60})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Small MM), Pivot(attribute:OLAY, aggregates:{ sum_qty = 3, sum_gross= 80.3})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Small MM), Pivot(attribute:GILLETTE, aggregates:{ sum_qty = 8, sum_gross= 50})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Small MM), Pivot(attribute:ORAL B, aggregates:{ sum_qty = 13, sum_gross= 250})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Large MM), pivotList:[Pivot(attribute:ARIEL, aggregates:{ sum_qty=9, sum_gross=300 }),
Pivot(attribute:GILLETTE, aggregates:{ sum_qty = 12, sum_gross= 103.88}),Pivot(attribute:OLAY, aggregates:{ sum_qty = 8, sum_gross= 60})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Small MM), Pivot(attribute:GILLETTE, aggregates:{ sum_qty = 8, sum_gross= 50})]),
Pivot(attribute:OLAY, aggregates:{ sum_qty = 3, sum_gross= 80.3}),Pivot(attribute:ORAL B, aggregates:{ sum_qty = 13, sum_gross= 250})])
Mini Market:
    Large MM:
        ARIEL: {sum_qty = 9, sum_gross= 300}
        GILLETTE: {sum_qty = 12, sum_gross= 103.88}
        OLAY: {sum_qty = 8, sum_gross= 60}

Mini Market:
    Small MM:
        GILLETTE: {sum_qty = 8, sum_gross= 50}
        OLAY: {sum_qty = 3, sum_gross= 80.3}
        ORAL B: {sum_qty = 13, sum_gross= 250}
简单地说,我希望嵌套如下:

SalesCollector collector = new SalesCollector(groups);
        final Map<String, Map<String, Map<String, PivotTable>>> results = salesRecords.stream()
            .collect(groupingBy(SalesRecord::getChannel(), TreeMap::new,
                groupingBy(SalesRecord::getCategoryName(), TreeMap::new,
                    groupingBy(SalesRecord::getBrand(), TreeMap::new, collector))));

List<PivotTable> myList = results.values().stream()
            .map(Map::values)
            .flatMap(Collection::stream)
            .map(Map::values)
            .flatMap(Collection::stream)
            .collect(Collectors.toList());
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Large MM), Pivot(attribute:ARIEL, aggregates:{ sum_qty=9, sum_gross=300 })])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Large MM), Pivot(attribute:GILLETTE, aggregates:{ sum_qty = 12, sum_gross= 103.88})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Large MM), Pivot(attribute:OLAY, aggregates:{ sum_qty = 8, sum_gross= 60})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Small MM), Pivot(attribute:OLAY, aggregates:{ sum_qty = 3, sum_gross= 80.3})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Small MM), Pivot(attribute:GILLETTE, aggregates:{ sum_qty = 8, sum_gross= 50})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Small MM), Pivot(attribute:ORAL B, aggregates:{ sum_qty = 13, sum_gross= 250})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Large MM), pivotList:[Pivot(attribute:ARIEL, aggregates:{ sum_qty=9, sum_gross=300 }),
Pivot(attribute:GILLETTE, aggregates:{ sum_qty = 12, sum_gross= 103.88}),Pivot(attribute:OLAY, aggregates:{ sum_qty = 8, sum_gross= 60})])
PivotTable(pivot:[Pivot(attribute:Mini Market), Pivot(attribute:Small MM), Pivot(attribute:GILLETTE, aggregates:{ sum_qty = 8, sum_gross= 50})]),
Pivot(attribute:OLAY, aggregates:{ sum_qty = 3, sum_gross= 80.3}),Pivot(attribute:ORAL B, aggregates:{ sum_qty = 13, sum_gross= 250})])
Mini Market:
    Large MM:
        ARIEL: {sum_qty = 9, sum_gross= 300}
        GILLETTE: {sum_qty = 12, sum_gross= 103.88}
        OLAY: {sum_qty = 8, sum_gross= 60}

Mini Market:
    Small MM:
        GILLETTE: {sum_qty = 8, sum_gross= 50}
        OLAY: {sum_qty = 3, sum_gross= 80.3}
        ORAL B: {sum_qty = 13, sum_gross= 250}

是否有可能用相同分组的集电器结果本身实现这一点?实现这一点的最佳方法是什么?

我通过缺少的
收集器扩展了您的流。它是一个专用的
收集器
,将每个
销售记录
映射到
映射
。由于
Map
有一个值类型,我决定使用
Double

    Supplier<Map<String, Double>> supplier = TreeMap::new;
    BiConsumer<Map<String, Double>, SalesRecord> biConsumer = (map, sr) -> {
        map.merge("sum_qty", Double.valueOf(sr.getQty()), (qtySum, qty) -> qtySum + qty);
        map.merge("sum_gross", sr.getGross(), (grossSum, gross) -> grossSum + gross);
    };
    BinaryOperator<Map<String, Double>> binaryOperator = (l, r) -> {
        l.compute("sum_qty", (k, v) -> v + r.get("sum_qty"));
        l.compute("sum_gross", (k, v) -> v + r.get("sum_gross"));
        return l;
    };
    Collector<SalesRecord, Map<String, Double>, Map<String, Double>> collector = Collector.of(supplier, biConsumer, binaryOperator);

你能分享数据透视表和销售记录吗?另外,您现在期望的结果的数据类型是什么?@nullpointer我已经添加了POJO。据我所见,结果预期id列表的数据类型为SalesCollector
/
累加器
构建总和。为什么要在
SalesCollector
acculator
之间使用代码?是的。你问“用同样的分组集电器结果本身是否可能达到这个效果?”我回答了。还有:“实现这一目标的最佳方式是什么?”我不想说,我的答案显示了最好的方法,但我认为显示的代码比
SalesCollector
/
Accumulator
的开销要小。因此,我现在的问题是,如何将输出改为列表,而不映射Pivot的“属性”是渠道/类别/品牌的值,而聚合是总和值?我不确定是否理解您的建议问题变量
grouped
对应于
Pivot
的字段
aggregates
。但是我不知道Pivot.attribute的目的是什么。这是因为分组可以分为多个级别,而不仅仅是三个级别。如果我只是将结果作为Map返回,那么我需要根据分组级别将结果设置为多个Map变量。例如,对于2层,3层的分组映射将是映射。相反,我试图实现的是以列表的形式返回结果,而不管分组的级别如何。