java - 如何在 Java 8 中使用 groupby 函数计算计数?
问题描述
如何使用带有计数功能的 groupby ?
我有以下数据,我想要以下输出:
期望的输出:
Stock | TOTAL | INPROGRESS | CANCEL | COMPLETED
-----------------------------------------------
HCL | 4 | 2 | 1 | 1
TCS | 5 | 2 | 0 | 2
注意:我将此数据存储在哈希图中。键: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
}
解决方案
我会这样做:
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。
推荐阅读
- r - 如何删除 R-Markdown 块输出中奇怪字符的显示?
- c++ - 从文件读取和写入
- generics - 创建一个绑定到整数类型的泛型函数
- python - 如何理解下面的 crontab?我知道结构,但找不到合适的来源来清楚地解释它
- javascript - 如何从复选框中获取选定的多个值并以表单形式提交以获取匹配的搜索结果
- javascript - 试图找出如何使用“this”来处理单个菜单项
- reactjs - 在 react-final-form 中更新输入模糊的值
- webrtc - 是否可以像处理 HTTP 请求一样对 WebRTC 连接进行逆向工程或重放?
- css - Nuxt.js 的背景图像没有响应
- c++ - 为什么 C++ 在标准库中没有 std::thread_pool?