【问题标题】:how to make getting average data by month more efficient如何更有效地按月获取平均数据
【发布时间】:2016-11-02 14:16:54
【问题描述】:

您好,我有两段长代码,我觉得可以提高效率,但我似乎想不出办法。

基本上,我有一个报告列表,我遍历与记录日期匹配的列表以获取某一年的所有报告。

接下来我为每个月创建了 12 个列表,以按月分隔报告。

基本上我在年度列表中逐一检查该年度的每个报告并检查月份的字符并将它们分开如下-

for (int i = 0; i < yearlyReportList.size(); i++) {
        if (yearlyReportList.get(i).getDateTime().charAt(5) == '0' && yearlyReportList.get(i).getDateTime().charAt(6) == '1') {
            janReports.add(yearlyReportList.get(i));
        }
        if (yearlyReportList.get(i).getDateTime().charAt(5) == '0' && yearlyReportList.get(i).getDateTime().charAt(6) == '2') {
            febReports.add(yearlyReportList.get(i));
        }
        if (yearlyReportList.get(i).getDateTime().charAt(5) == '0' && yearlyReportList.get(i).getDateTime().charAt(6) == '3') {
            marchReports.add(yearlyReportList.get(i));
        }
....

接下来我像这样平均每个月需要的数据-我几乎复制并粘贴了 12 次,然后每个月都更改它-

if (janReports.size() == 0) {
        avgJanData = 0;
    } else {
        for (int i = 0; i < janReports.size(); i++) {
            janDataSum = janDataSum + janReports.get(i).getData();
        }

        avgJanData = janDataSum / janReports.size();
    }
....

但是必须有一种更有效的方法,然后像这样复制粘贴这段代码对吗?

谁能给我一个如何让这段代码更好的例子?

感谢您的帮助。

【问题讨论】:

  • 使用嵌套的 if 语句。最外层只测试条件yearlyReportList.get(i).getDateTime().charAt(5) == '0'。对于另一个块,您可以使用forEach 循环浏览月度报告。

标签: java average


【解决方案1】:

你可以从你的代码 sn-p 中提取一个方法:

public float average(Collection<Report> reports) {

    for (int i = 0; i < janReports.size(); i++) {
        janDataSum = janDataSum + janReports.get(i).getData();
    }


    return janDataSum / janReports.size();
}

然后你每个月调用这个方法。

如果您使用的是 Java 8,其他解决方案:

 janRepors.stream().mapToDouble(o -> o.getData()).average(); // this will return the average as a double.

相同:每个月都调用它。

关于您的代码的全局提示: 您还可以使用 Map 使用月份号作为键来存储您的 Reports 而不是 12 变量,它应该可以简化您的代码。

【讨论】:

    【解决方案2】:

    首先我建议你摆脱丑陋的yearlyReportList.get(i).getDateTime().charAt(5) == '0' &amp;&amp; yearlyReportList.get(i).getDateTime().charAt(6) == '1'

    让我们获取 int 中的月份数。

    Integer.parseInt(yearlyReportList.get(i).getDateTime().substring(5, 6))
    

    如果您告诉我们日期的格式,我们可以以更“自然”的方式(通过解析日期和提取月份)来做到这一点。

    现在让我们来解决您的复制粘贴问题。

    我建议制作数组并一次性填写

    int[] sumsByMonth = new int[12];
    int[] countsByMonth = new int[12];
    for(Report report: yearlyReportList) {
         int month = Integer.parseInt(r.getDateTime().substring(5, 6));
         sumsByMonth[month - 1] += r.getData();
         countsByMonth[month - 1]++;
    }
    

    数组默认填充0

    你现在要做的就是用总和除以计数

    double[] averagesByMonth = new double[12];
    for(int i = 0; i<12; i++) {
        averagesByMonth[i] = ((double)sumsByMonth[i])/countsByMonth[i];
    }
    

    从整数除法切换到双除法需要转换为double

    更新

    你最好用这个来提取月份:

            SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
            Date date = format.parse(report.getDateTime());
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            int month = calendar.get(Calendar.MONTH);
    

    在这种情况下,您将获得基于月份的 0,并且在访问数组时无需减去 1

    【讨论】:

    • 我们有一个日期时间存储为 yyyy/MM/dd HH:mm:ss...谢谢
    • 因为我们的日期时间存储在 01 - 12 之间,我们不必像这样将它们添加到数组中 --sumsByMonth[month - 1] += r.getData(); ?因为在这种情况下,它将在 sumsByMonth[1] 和 12 月在 sumsByMonth[12] 添加,因为 sumsByMonth[11] 是最后一个,对吗?
    • @GarudaAiacos 是的。我修正了我的答案。
    • 如果您不介意提供帮助,我还有一个问题...由于某种原因,该代码在两位数月份无法正常工作...现在我们只有 11 月的报告...它应该存储在点 [10] 中,但由于某种原因它没有注册为 [1] 而不是在一月的位置。
    • substring参数有问题。您可以调整它们或使用更新中的方法,这无论如何都会更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多