如何使用 java 流对字段进行分组并创建摘要
how to use java stream to group fields and create a summary
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 流和收集器来做到这一点?
以下内容收集到状态 -> 百分比图,然后您可以将其转换为输出模型。此代码采用 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()));
并进一步计算 List
中类型 CallSummary
的摘要:
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
计数由您使用与 ItemSummary
中选择的数据类型对齐的签名 int percentage(long val, long total)
实现。
示例结果:
[
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)])
]
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 流和收集器来做到这一点?
以下内容收集到状态 -> 百分比图,然后您可以将其转换为输出模型。此代码采用 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()));
并进一步计算 List
中类型 CallSummary
的摘要:
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
计数由您使用与 ItemSummary
中选择的数据类型对齐的签名 int percentage(long val, long total)
实现。
示例结果:
[
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)])
]