递归DRY代码,计算月份的天数,Java

Recursively DRY code,calculate days of months,Java

你会如何递归地干燥这段代码以避免重复一个月中的几天。

我有一个想法,为一月份设置一个基本案例,并通过递归计算上个月的 dayOfYear 来处理其他月份,然后将当前月份添加到其中。 像 if (month == 1) { ... } else { ... dayOfYear(month-1, dayOfMonth, year) ... } correct 但我不太确定实施方式,也不确定这是否是一种准确的方法。

假设我有一个这样的数组,我可以在其中存储我所有的日子 int[] monthLengths = new int[] { 31, 28, 31, 30, ..., 31}

public static int dayOfYear(int month, int dayOfMonth, int year) {
if (month == 2) {
    dayOfMonth += 31;
} else if (month == 3) {
    dayOfMonth += 59;
} else if (month == 4) {
    dayOfMonth += 90;
} else if (month == 5) {
    dayOfMonth += 31 + 28 + 31 + 30;
} else if (month == 6) {
    dayOfMonth += 31 + 28 + 31 + 30 + 31;
} else if (month == 7) {
    dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30;
} else if (month == 8) {
    dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30 + 31;
} else if (month == 9) {
    dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31;
} else if (month == 10) {
    dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30;
} else if (month == 11) {
    dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31;
} else if (month == 12) {
    dayOfMonth += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 31;
}
return dayOfMonth;

}

您可以使用数组将月份映射到月份的天数总和,并且您应该根据年份添加一个偏移量。

private static int[] daysTillMonth = ...

public static int dayOfYear(int month, int dayOfMonth, int year) {
   return daysTillMonth[month] + dayOfMonth + month>1?yearOffset(year):0;
}

private int yearOffset(int year) {
   // implement
}

您也可以编写一个数学方程来计算这个,例如:

public static int dayOfYear(int month, int dayOfMonth, int year) {
   int n1 = (275 * month / 9)
   int n2 = ((month + 9) / 12)
   int n3 = (1 + ((year - 4 * (year / 4) + 2) / 3))
   int n = n1 - (n2 * n3) + dayOfMonth - 30
   return n;
}

您的代码将以多种方式失败...

2 月并不总是 28 天...

您需要学习使用 java 为您开发的 API!

另一方面...您发布的代码中没有任何与递归相关的内容...您甚至不需要这样...

我的建议是:

public static long dayOfYear(int month, int dayOfMonth, int year) {
    return ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.of(year, month, dayOfMonth));
}

您可以初始化第二个数组:

private static int[] monthLengths = new int[] { 31, 28, 31, 30, ..., 31};
private static int[] monthStart = new int[12];
static {
    for (int i = 1; i < monthStart.length; ++i) {
        monthStart[i] = monthStart[i-1] + monthLength[i-1];
    }
}

正如其他答案中所建议的那样,您可以轻松地避免递归,只需用一年中的第一天和一个月中的第一天之间的天数填充数组。 因为从复杂性的角度来看,递归将采用 O(n) 和具有预定义数组的算法 - O(1)

但是如果你真的想使用递归,你可以在一些准备好的数组中填充天数,然后使用 month 作为数组的索引进行计算。

例如:

public static int[] daysOfMonth = new int[]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

public int daysOfYear(int day, int month, int year) {
    if (month == 0) {
        return day;
    }
    //specific case for leap year
    int leapOffset = 0;
    if (month == 2) {
        if (Year.of(year).isLeap()) {
            leapOffset = 1;
        }
    }
    return daysOfYear(day + daysOfMonth[month-1] + leapOffset, month - 1, year);
}

并测试:

@Test
public void testDay() {
    Assert.assertEquals(LocalDate.of(2015, Month.FEBRUARY, 25).getDayOfYear(), daysOfYear(25, 1, 2015));
    Assert.assertEquals(LocalDate.of(2014, Month.MARCH, 25).getDayOfYear(), daysOfYear(25, 2, 2014));
    Assert.assertEquals(LocalDate.of(2013, Month.MAY, 25).getDayOfYear(), daysOfYear(25, 4, 2013));
    Assert.assertEquals(LocalDate.of(2012, Month.JUNE, 25).getDayOfYear(), daysOfYear(25, 5, 2012));
}