递归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));
}
你会如何递归地干燥这段代码以避免重复一个月中的几天。
我有一个想法,为一月份设置一个基本案例,并通过递归计算上个月的 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));
}