如何在Java中创建一个形成特殊可打印字符串的收集器?

问题描述 投票:0回答:1

我需要实现这个方法:

public Collector<CourseResult, ?, String> printableStringCollector() {

返回一个

Collector
,形成特殊的可打印
String
,如下所述。

它是多行

String
,包含所有结果、总值和分数的格式化表格。

表格的格式应满足以下要求:

  • 标题为必填项。
  • 列宽取决于值的长度。
  • 行按学生的姓氏排序。
  • 列按任务名称排序。
  • 双精度值显示为小数点后 2 位。
  • “Mark”列的值由平均总分定义。
  • 注意不同列的对齐。

到目前为止我写了这段代码:

public Collector<CourseResult, ?, String> printableStringCollector() {
    return Collector.of(

        StringBuilder::new,
        (sb, courseResult) -> {
            Person person = courseResult.getPerson();
            Map<String, Integer> taskResults = courseResult.getTaskResults();

            List<String> taskNames = taskResults.keySet().stream().sorted().collect(Collectors.toList());

            // Calculate the total score and average mark
            int totalScore = taskResults.values().stream().reduce(0, Integer::sum);
            double averageMark = (double) totalScore / taskResults.size();
            // Append the formatted row to the StringBuilder
            sb.append(String.format("%-16s", person.getLastName() + " " + person.getFirstName()));
            for (String taskName : taskNames) {
                sb.append(String.format("|%-12s", taskResults.getOrDefault(taskName, 0)));
            }
            sb.append(String.format("|%-10.2f|%-5s|\n", averageMark, calculateMark(averageMark)));
        },

        // Combiner: Combine two StringBuilders by concatenating their contents
        (sb1, sb2) -> sb1.append(sb2.toString()),

        // Finisher: Return the final formatted table string
        StringBuilder::toString);
}

private String calculateMark(double avg) {
    return avg > 90 ? "A" 
        : avg >= 83 ? "B" 
            : avg >= 75 ? "C" 
                : avg >= 68 ? "D" 
                    : avg >= 60 ? "E" 
                        : "F";
}

如何添加带有字符串“Student”和任务名称的标题?

示例:

Student........|Phalaxing |Shieldwalling |Tercioing |Wedging |Total |Mark |
Eco Betty......|0 ........|83............|89........|59......|57.75 |F ...|
Lodbrok Johnny |61 .......|92............|67........|0.......|55.00 |F....|
Paige Umberto..|75....... |94............|0.........|52......|55.25 |F....|
Average........|45.55.... |89.67.........|52.00.....|37.00...|56.00 |F....|
java java-stream
1个回答
0
投票

@Ksenia,在“Finisher”功能中,而不是这个

        // Finisher: Return the final formatted table string
        StringBuilder::toString);

你可以实现任何类型的逻辑...

        // Finisher: Return the final formatted table string
        sb -> {
            StringBuilder headerRow = new StringBuilder();
            // Build the header in headerRow with proper column widths using keys and task names
            // E.g. Student........|Phalaxing |Shieldwalling |Tercioing |Wedging |Total |Mark |
            sb.insert(0, headerRow); // This inserts the header at the first position in the string builder
            // You may prepare the average row also similarly, and append at the end
            StringBuilder avgRow = new StringBuilder();
            // Build average row here
            sb.append(avgRow);
            return sb.toString();
        });

此外,由于您必须正确格式化字符串,因此您必须首先找到所有列的最大长度。因此,您可能需要遍历 CourseResult 两次。一次从所有名称和任务名称中获取最大长度以确定长度。 这应该在调用

Collector.of()
之前完成。 因此,在
Combiner
Finisher
中,这些长度已经可用。

© www.soinside.com 2019 - 2024. All rights reserved.