public class Call {
private String status;
private String callName;
}
我有一个通话清单,我必须创建一个摘要,像这样:
public class CallSummary {
private String callName;
private List<ItemSummary> items;
}
public class itemSummary {
private String status;
private Integer percentage;
}
我的目标是显示具有一定状态的通话百分比像:
INBOUND_CALL : {
FAILED = 30%
SUCCESS = 70%
}
我如何使用Java 8 Stream和Collector做到这一点?
以下内容收集到状态->百分比图,然后可以将其转换为输出模型。此代码假定为getStatus
方法。
List<Call> calls;
Map<String,Double> statusPercents = calls.stream()
.collect(Collectors.groupingBy(Call::getStatus,
Collectors.collectingAndThen(Collectors.counting(),
n -> 100.0 * n / calls.size())));
我意识到这段代码有点难以阅读。收集链按状态对呼叫进行分组,然后对每个组进行计数,最后转换为百分比。您可以(可以说)通过为收集器设置临时变量来使其更具可读性:
var percentFunction = n -> 100.0 * n / calls.size();
var collectPercent = collectingAndThen(count(), percentFunction);
var collectStatusPercentMap = groupingBy(Call::getStatus, collectPercent);
您还希望按通话名称分组,但这实际上是一样的-使用groupingBy
,然后将通话列表减少到CallSummary
。
分组的想法是嵌套,这样您可以拥有一个呼叫名称,然后可以进行基于状态的计数查找。我也建议对状态使用枚举
enum CallStatus {
FAILED, SUCCESS
}
并在其他类中将其改编为
class Call {
private CallStatus status;
private String callName;
}
然后您可以实现嵌套分组,并从中间结果开始,例如:
List<Call> sampleCalls = List.of(new Call(CallStatus.SUCCESS,"naman"),new Call(CallStatus.FAILED,"naman"),
new Call(CallStatus.SUCCESS,"diego"), new Call(CallStatus.FAILED,"diego"), new Call(CallStatus.SUCCESS,"diego"));
Map<String, Map<CallStatus, Long>> groupedMap = sampleCalls.stream()
.collect(Collectors.groupingBy(Call::getCallName,
Collectors.groupingBy(Call::getStatus, Collectors.counting())));
这将为您输出
{diego={FAILED=1, SUCCESS=2}, naman={FAILED=1, SUCCESS=1}}
您还可以进一步评估百分比。 (尽管在Integer
中表示它们可能会失去精度,具体取决于您如何进一步评估它们。)
为了进一步解决,您可以为基于名称的计数查找保留另一个Map
:
Map<String, Long> nameBasedCount = calls.stream()
.collect(Collectors.groupingBy(Call::getCallName, Collectors.counting()));
此外,将CallSummary
中类型为List
的摘要计算为:
List<CallSummary> summaries = groupedMap.entrySet().stream()
.map(entry -> new CallSummary(entry.getKey(), entry.getValue().entrySet()
.stream()
.map(en -> new ItemSummary(en.getKey(), percentage(en.getValue(),
nameBasedCount.get(entry.getKey()))))
.collect(Collectors.toList()))
).collect(Collectors.toList());
其中percentage
计数由您也使用与int percentage(long val, long total)
中选择的数据类型对齐的签名ItemSummary
来实现。
样本结果:
[
CallSummary(callName=diego, items=[ItemSummary(status=FAILED, percentage=33), ItemSummary(status=SUCCESS, percentage=66)]),
CallSummary(callName=naman, items=[ItemSummary(status=FAILED, percentage=50), ItemSummary(status=SUCCESS, percentage=50)])
]