【问题标题】:How to calculate count using groupby function in Java 8?如何在 Java 8 中使用 groupby 函数计算计数?
【发布时间】:2020-09-09 10:58:13
【问题描述】:

groupby如何使用计数功能?

我有以下数据,我想要以下输出:

期望的输出:

Stock | TOTAL | INPROGRESS | CANCEL | COMPLETED
-----------------------------------------------
HCL   |     4 |          2 |      1 |        1
TCS   |     5 |          2 |      0 |        2

注意:我将这些数据存储在 hashmap 中。键:OrderId,值:OrderModel(PairName,状态)

我可以用下面的代码来实现。但我想要更正确的代码。如果您有其他方法,请建议我。

public static void main(String[] args) {

        Map<Integer, Model> test = new HashMap<Integer, Model>();

        Model m1 = new Model("HCL", "Inprogress");
        Model m2 = new Model("HCL", "Cancel");
        Model m3 = new Model("HCL", "Inprogress");
        Model m4 = new Model("HCL", "Completed");

        Model a1 = new Model("TCS", "Inprogress");
        Model a2 = new Model("TCS", "Inprogress");
        Model a3 = new Model("TCS", "Inprogress");
        Model a4 = new Model("TCS", "Completed");
        Model a5 = new Model("TCS", "Completed");

        int count = 1;

        test.put(count++, m1);
        test.put(count++, m2);
        test.put(count++, m3);
        test.put(count++, m4);

        test.put(count++, a1);
        test.put(count++, a2);
        test.put(count++, a3);
        test.put(count++, a4);
        test.put(count, a5);

        Map<String, Model> countPair = new HashMap<String, Model>();

        test.forEach((k, v) -> System.out.println("Key:" + k + " Pair:" + v.getName() + " Status:" + v.getStatus()));

        System.out.println(" With Count !!!!");
        List<Model> list = new ArrayList<Model>();

        test.entrySet().stream().forEach(e -> list.add(e.getValue()));

        // Total
        Map<String, Long> counted = list.stream().collect(Collectors.groupingBy(Model::getName, Collectors.counting()));
        counted.forEach((k, v) -> {
            countPair.put(k, new Model.ModelBuilder().setTotal(v).build());
        });

        // Inprogress
        counted = list.stream().filter(e -> e.getStatus().equals("Inprogress"))
                .collect(Collectors.groupingBy(Model::getName, Collectors.counting()));
        counted.forEach((k, v) -> countPair.get(k).setInProgressCount(v));

        // Cancel
        counted = list.stream().filter(e -> e.getStatus().equals("Cancel"))
                .collect(Collectors.groupingBy(Model::getName, Collectors.counting()));
        counted.forEach((k, v) -> countPair.get(k).setCancelCount(v));

        // Completed
        counted = list.stream().filter(e -> e.getStatus().equals("Completed"))
                .collect(Collectors.groupingBy(Model::getName, Collectors.counting()));
        counted.forEach((k, v) -> countPair.get(k).setCompletedCount(v));

        countPair.forEach((k, v) -> System.out.println("Pair : " + k + " : " + v.getTotal() + " , "
                + v.getInProgressCount() + " , " + v.getCancelCount() + " , " + v.getCompletedCount()));

    }

型号:

public class Model {

    private String name;
    private String status;

    private long total;
    private long inProgressCount;
    private long completedCount;
    private long cancelCount;

    static class ModelBuilder {
        private long total;
        private long inProgressCount;
        private long completedCount;
        private long cancelCount;

        public ModelBuilder setTotal(long total) {
            this.total = total;
            return this;
        }

        public ModelBuilder setInProgressCount(long inProgressCount) {
            this.inProgressCount = inProgressCount;
            return this;
        }

        public ModelBuilder setCompletedCount(long completedCount) {
            this.completedCount = completedCount;
            return this;
        }

        public ModelBuilder setCancelCount(long cancelCount) {
            this.cancelCount = cancelCount;
            return this;
        }

        public Model build() {
            return new Model(this);
        }

    }

    public Model(ModelBuilder modelBuilder) {
        this.total = modelBuilder.total;
        this.inProgressCount = modelBuilder.inProgressCount;
        this.completedCount = modelBuilder.completedCount;
        this.cancelCount = modelBuilder.cancelCount;
    }

    public Model(String name, String status) {
        super();
        this.name = name;
        this.status = status;
    }
//getter and setter
}

【问题讨论】:

  • "我可以使用以下代码实现。但我想要更正确的代码" 那么您的代码是否有效?如果它不起作用,你真的能说你已经“达到”了你的目标吗?我想你真正想要的是更简洁代码之类的?

标签: java performance java-stream


【解决方案1】:

我会这样做:

List<Model> test = Arrays.asList(
        new Model("HCL", "Inprogress"),
        new Model("HCL", "Cancel"),
        new Model("HCL", "Inprogress"),
        new Model("HCL", "Completed"),
        new Model("TCS", "Inprogress"),
        new Model("TCS", "Inprogress"),
        new Model("TCS", "Inprogress"),
        new Model("TCS", "Completed"),
        new Model("TCS", "Completed")
);

Map<String, Map<String, Long>> result = test.stream()
        .collect(Collectors.groupingBy(Model::getName,
                     Collectors.groupingBy(Model::getStatus,
                         Collectors.counting())));

result.entrySet().forEach(System.out::println);

输出

HCL={Cancel=1, Completed=1, Inprogress=2}
TCS={Completed=2, Inprogress=3}

使用 result 对象产生所需的输出应该不是问题,因为所有繁重的工作已经完成。

System.out.println("Stock | TOTAL | INPROGRESS | CANCEL | COMPLETED");
System.out.println("-----------------------------------------------");
for (Entry<String, Map<String, Long>> nameEntry : result.entrySet()) {
    String name = nameEntry.getKey();
    Map<String, Long> statusCounts = nameEntry.getValue();
    long inprogress = statusCounts.getOrDefault("Inprogress", 0L);
    long cancel     = statusCounts.getOrDefault("Cancel"    , 0L);
    long completed  = statusCounts.getOrDefault("Completed" , 0L);
    System.out.printf("%-5s | %5d | %10d | %6d | %8d%n", name,
                      inprogress + cancel + completed,
                      inprogress, cancel, completed);
}

输出

Stock | TOTAL | INPROGRESS | CANCEL | COMPLETED
-----------------------------------------------
HCL   |     4 |          2 |      1 |        1
TCS   |     5 |          3 |      0 |        2

注意:将其与问题中的“期望输出”进行比较,我们发现问题示例是错误的,因为TCS, INPROGRESS 是 3,而不是 2。

【讨论】:

    【解决方案2】:

    我同意 Andreas 关于最佳流解决方案的观点。 但是因为你用性能标记了它,所以我会说我们应该比较执行时间,所以我确实比较了 vijayk 解决方案与 Andreas 解决方案以及没有流的解决方案。

    以下是列表中 9 个对象的结果:

    Total execution with stream in ms: 7.642649ms
    Total execution with for each in ms: 0.037637ms
    Total execution with Andreas stream in ms: 0.392906ms
    foreach was faster than vijayk by : 203.06211972261337
    Andreas was faster than vijayk by : 19.451596565081726
    foreach was faster than Andreas by : 10.439354890134707
    

    以下是列表中 18 000 000 个对象的结果:

    Total execution with stream in ms: 703.025082ms
    Total execution with for each in ms: 278.319758ms
    Total execution with Andreas stream in ms: 504.190017ms
    foreach was faster than vijayk by : 2.5259618183485197
    Andreas was faster than vijayk by : 1.3943653350835783
    foreach was faster than Andreas by : 1.8115494948080546
    

    然后我将流更改为并行流,结果如下所示

    对于列表中的 9 个对象:

    Total execution with stream in ms: 20.937947ms
    Total execution with for each in ms: 0.042329ms
    Total execution with Andreas stream in ms: 0.496791ms
    foreach was faster than vijayk by : 494.64780646837863
    Andreas was faster than vijayk by : 42.14638952799064
    foreach was faster than Andreas by : 11.736421838455906
    

    对于列表中的 18 000 000 个对象:

    Total execution with stream in ms: 476.563756ms
    Total execution with for each in ms: 278.438998ms
    Total execution with Andreas stream in ms: 302.730519ms
    foreach was faster than vijayk by : 1.7115553475738337
    Andreas was faster than vijayk by : 1.5742177484259523
    foreach was faster than Andreas by : 1.087241805833535
    

    对于每个解决方案看起来像这样:

    for (Model item : list) {
            Model itemToIncrease;
            if (countPair.containsKey(item.getName())) {
                itemToIncrease = countPair.get(item.getName());
            } else {
                countPair.put(item.getName(), item);
                itemToIncrease = item;
            }
            itemToIncrease.increaseTotal();
            switch (item.getStatus()) {
                case "Inprogress":
                    itemToIncrease.increaseInProgressCount();
                    break;
                case "Cancel":
                    itemToIncrease.increaseCancelCount();
                    break;
                case "Completed":
                    itemToIncrease.increaseCompletedCount();
                    break;
            }
    }
    

    总结一下,当您拥有大量数据时,我会说 Andreas 解决方案非常好

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-08
      • 2022-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多