如何返回一个收集器,形成一个特殊的可打印字符串在Java?

2uluyalo  于 2023-04-28  发布在  Java
关注(0)|答案(1)|浏览(141)

我需要实现这个方法:public Collector〈CourseResult,?,String〉printableStringCollector(){,其返回形成如下所述的特殊可打印String的收集器。
它是一个多行字符串,包含所有结果、总值和标记的格式化表格。表格的格式应满足以下要求:
需要标头。
列宽取决于值的长度。
行按学生的姓氏排序。
列按任务名称排序。
双精度值显示,小数点后2位数字。
“泥灰岩”列的值由平均总分定义。
注意不同列的对齐。
到目前为止,我写了这段代码:

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";
}

如何添加一个带有String“Student”和taskName的头文件:
示例:

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....|
j5fpnvbx

j5fpnvbx1#

@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()之前完成。因此,在CombinerFinisher中,这些长度已经可用。

相关问题