如何使用Java流对字段进行分组并创建摘要

问题描述 投票:2回答:2
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做到这一点?

java java-stream collectors
2个回答
0
投票

以下内容收集到状态->百分比图,然后可以将其转换为输出模型。此代码假定为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


0
投票

分组的想法是嵌套,这样您可以拥有一个呼叫名称,然后可以进行基于状态的计数查找。我也建议对状态使用枚举

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)])
]
© www.soinside.com 2019 - 2024. All rights reserved.