[英]using Java 8 How to filter by list and group by based on filter condition and convert to Map with their count
我想将下面的 for 循环转换为 Java 8。但是在过滤状态列表和分组为一个状态和总数时遇到问题。 我试过了,但是对于每个"LIVE"
、 "DRAFT"
、 "TEST"
必须循环 3 次并获得 3 个不同的地图。 是否可以使用 Java-8 进入一个循环?
其中"LIVE"
、 "DRAFT"
和"TEST"
再次是来自workflowInstance
的状态组合,例如DRAFT = {"DRAFT_EDIT","DRAFT_SAVE"}
。 我想根据定义的这个组合将所有状态分类为 3。
Map<String, Integer> summaryMap = new HashMap<>();
int l = 0, d = 0, t = 0;
for (WorkflowInstance instance : workflowInstances) {
if (liveStatuses.contains(instance.getStatus())) {
summaryMap.put("LIVE", l++);
} else if (testStatuses.contains(instance.getStatus())) {
summaryMap.put("TEST", t++);
} else if (draftStatuses.contains(instance.getStatus())) {
summaryMap.put("DRAFT", d++);
}
}
Java-8 分别用于"LIVE"
、 "DRAFT"
和"TEST"
:
map.put("DRAFT", workflowInstances.stream()
.filter(inst-> Constants.DRAFT_STATUS.contains(inst.getStatus()))
.collect(Collectors.groupingBy(WorkflowInstance::getStatus, Collectors.counting()))
.entrySet().stream().mapToLong(e-> e.getValue()).sum()
);
map.put("LIVE", workflowInstances.stream()
.filter(inst-> Constants.LIVE_STATUS.contains(inst.getStatus()))
.collect(Collectors.groupingBy(WorkflowInstance::getStatus, Collectors.counting()))
.entrySet().stream().mapToLong(e-> e.getValue()).sum()
);
// Similar for "TEST"
我不想循环 3 次,而是想在 1 个 go 中对它们进行分类。 任何帮助,将不胜感激。
我认为您需要做的就是创建一个更复杂的分组 function ,它将getStatus
转换为您想要的三种类型之一。 你可以尝试这样的事情:
Map<String, Long> summaryMap = workflowInstances.stream()
.groupingBy(a -> {
if (liveStatuses.contains(a.getStatus())) {
return "LIVE";
} else if (testStatuses.contains(a.getStatus())) {
return "TEST";
} else if (draftStatuses.contains(a.getStatus())) {
return "DRAFT";
}
}, Collectors.counting());
无论如何,您都无法避免提取状态的类型。 为它创建一个专用方法(我想作为liveStatuses
等的状态列表是 static 或实例变量。请注意,您忘记处理没有任何预定义状态与当前状态匹配的情况。在这种情况下,让我们使用"UNDEFINED"
:
String extractStatus(WorkflowInstance workflowInstance) {
String status = workflowInstance.getStatus();
if (liveStatuses.contains(status)) {
return "LIVE";
} else if (testStatuses.contains(status)) {
return "TEST";
} else if (draftStatuses.contains(status)) {
return "DRAFT";
}
return "UNCATEGORIZED"; // in case nothing is matched
}
然后使用Collectors.groupingBy
和Collectors.counting
的组合进行收集相当容易:
Map<String, Long> map = workflowInstances.stream()
.collect(Collectors.groupingBy( // groups to Map
this::extractStatus, // extracted status is the key
Collectors.counting())); // value is a number of occurences
注意结果是Map<String, Long>
如果你坚持Map<String, Integer>
你需要一个额外的下游收集器使用Collectors.collectingAndThen
:
Map<String, Integer> map = workflowInstances.stream()
.collect(Collectors.groupingBy( // groups to Map
Foo::extractStatus, // extracted status is the key
Collectors.collectingAndThen( // value is collected ...
Collectors.counting(), // ... a number of occurences
count -> new BigDecimal(count) // ... as Integer from Long
.intValueExact()))); // ... but might throw an exception
如果数字超出范围,则会引发ArithmeticException
。 请记住, Long
的范围比Integer
更大。 Long
-> Integer
的转换方式有很多种,但原理相同。
...或使用Collectors.summingInt(e -> 1)
代替@HadiJ建议的Collectors.counting
的简单技巧。 它返回Integer
代替:
Map<String, Integer> map = workflowInstances.stream()
.collect(Collectors.groupingBy(this::extractStatus, Collectors.summingInt(e -> 1)));
检查此代码:我的解决方案添加一个枚举来处理不同类型的多个状态。
public static void main(String[] args) {
List<Instance> instances = new ArrayList<>();
instances.add(new Instance("LIVE"));
instances.add(new Instance("TEST"));
instances.add(new Instance("TEST"));
instances.add(new Instance("TEST"));
instances.add(new Instance("DRAFT"));
instances.add(new Instance("DRAFT"));
Map<String, Long> counts = instances.stream()
.collect(Collectors.groupingBy(a -> TemplateStatus.getStatus(a.getStatus()),Collectors.counting());
System.out.println(counts); //output: {DRAFT=2, TEST=3, LIVE=1}
}
class Instance {
public Instance(String status) {
this.status = status;
}
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
enum TemplateStatus {
LIVE("LIVE,LIVE2"), DRAFT("DRAFT,DRAFT_2"), TEST("TEST_1,TEST");
private List<String> status;
TemplateStatus(String s) {
status = Arrays.asList(s.split(","));
}
public static String getStatus(String s) {
if (LIVE.status.contains(s)) return "LIVE";
else if (TEST.status.contains(s)) return "TEST";
else if (DRAFT.status.contains(s)) return "DRAFT";
return "UNKNOWN";
}
}
希望这可以帮助你
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.