Creating calendar with array and loops using C#
我正在尝试创建一个应用程序,它告诉您输入2016年的日期(1月1日、9月3日等)的星期几(星期一、星期二等);输入是日期,输出是该日期的星期几。它必须用循环创建,例如for循环和if语句。我不能使用库函数。开始日期为2016年1月1日,星期五。这就是我目前为止所拥有的,我很迷茫:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public enum Days : byte { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }; public enum Months : byte { January, February, March, April, May, June, July, August, September, October, November, December }; class Program { public static void Main(string[] args) { const int numDays = 7; const int numMonths = 12; Months month = Months.Janurary; int monthCounter = 1; int[] daysinMonth = new int[numMonths] { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int[] daysofWeek = new int[numDays] {1, 2, 3, 4, 5, 6, 7}; Days dayOfWeek = Days.Sunday; dayOfWeek = Days.Friday; foreach (month in Months ) { |
我的小结是:
Using only the tools we have covered to date, find the weekday name of a specific date in 2016, working from Friday January 1 2016, using nested loops and comparisons.
既然你不想要代码,我会给你一些解释,只需要一点代码。然后,一旦这些都完成了,在这个底部有完整的代码,可以为您提供任意日期所需的所有信息。好的。
不过,您只对2016年感兴趣。因此,如果您希望todo是计算特定年份的星期几,则只需要(从完整代码中)类声明和两个函数:好的。
- GetDayNumberFromDate(开始日期)
- GetDayOfWeekFromDate
解释和一点代码
我会在一个静态类中完成所有这些。您不需要任何东西的
在该类中,我将声明并初始化三个私有变量:好的。
- 由12个整数组成的数组,每个整数表示每个月的天数。记住数组索引是从零开始的,所以您需要从一个月数(1-12)中减去一个来得到数组索引(0-11)。我还建议你发表评论,指出2016年是闰年,这就是为什么2月有29天
- 设置为2016的私有
const 整数(可能命名为YearOfInterest )。它表示数字2016的符号别名。consts让你的代码更容易维护(考虑一下,如果你的老师改变主意说"不,2014年就这么做",而你在2016年的代码中使用了6到8个位置——如果你有一个const ,你只需要更改其中一个位置。 - 这表明2016年1月1日是星期五。我将使用System.DayOfWeek枚举(是的,它是库代码,但是您所做的任何操作都将是一个字符一个字符地重复)。如果你愿意的话,你可以用你的
YearOfInterest const来做一些类似的事情(如果你的老师改变了对这一年的看法,这会使事情发生变化)。
这将是一个非常简单的声明,如下所示:好的。
1 |
我觉得这比说:好的。
1 | private readonly static DayOfWeek Jan1DayOfWeek = DayOfWeek.Friday; |
请记住,枚举开始编号(默认情况下)为零,所以星期日为0,星期六为6。好的。
完成后,我将创建两个函数:好的。
- 计算某一日期的
Day Number (即到该日期为止的一年中经过的天数(1月1日为1 ,2月3日为34 )。 - 调用
Day Number 函数(即获取整数)并返回一周中的某一天的函数。
第一个函数(我们称之为
- 它检查你的先决条件。因为这两个数字都是用户输入的,用户也会出错,所以您需要确保两个数字都大于或等于1,月数等于或小于12,日数等于或小于月内的天数(您很容易知道,它在您的数组中)(记住当索引到数组中)。如果不满足这些前提条件中的任何一个,则抛出异常。这很重要。如果有人输入了错误的数字,您很可能会从数组中索引(这将引发异常,但没有关于发生异常的原因的信息)。检查前提条件总是很好的
- 它循环您的"月份中的天数"数组,从数组的开始到输入月份的前一个月(减去1),求和天数。如果有人进入4月4日,您需要添加1月(31)、2月(29)和3月(31)的天数。这将使你到达月初(好吧,上个月的最后一天)。
- 它会在输入的月份的第几天进行添加—这将使您进入当前日期。
既然你想要在for循环上进行指导,那么这个循环最终会变成这样:好的。
1 2 3 4 | int dayCount = 0; for (int i = 0; i < month - 1; ++i) { dayCount += daysPerMonth[i]; } |
在循环结束时,
最后,最后一个函数(称为
有了这个数字,我将进行"模数7"运算(
如果结果是关闭的,不要感到惊讶(特别是如果结果是关闭了一个)。第一次把这件事做好是很困难的。调试就是从这里开始的。好的。
顺便说一下,我不会试图解析像"1月1日"这样的日期。你真的需要注意缩写(一月,二月,…),你会让那些不会拼写"二月"的人感到不安。只使用月和日整数。好的。
在所有这一切中,您会注意到一件事,那就是没有嵌套循环。不需要这样做,嵌套循环可能很昂贵。此代码循环已通过的月数(即少于12次)。如果你要循环数月和数天,你将循环12次30次(即大约366次)。12是较小的数字好的。完整代码如下:
我不知道你学到了什么,所以这基本上是在2005年左右。好的。
首先是一个带有一些基本"常量"的静态类:好的。
1 2 3 4 5 6 7 8 | static class FigureDate { private static readonly int[] _leapYearDaysPerMonth = new int[] { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; private static readonly int[] _normalYearDaysPerMonth = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; private const int YearZero = 1900; //Sunday is zero in DayOfWeek private readonly static DayOfWeek _day0 = new DateTime(YearZero, 1, 1).DayOfWeek; } |
(顺便说一下,dayofweek是在系统名称空间中定义的
我会在这个类中添加更多的东西——所有的东西(比如下面的所有函数)都在里面。好的。
首先,是一个特定的年份,一个闰年(要想知道这并不容易):好的。
1 2 3 4 5 6 7 8 9 10 | public static bool IsLeapYear (int year) { if (year % 400 == 0) { return true; } if (year % 100 == 0) { return false; } //otherwise return (year % 4) == 0; } |
然后我想,从"第0天"开始,闰年是如何过去的(幸运的是,1900年不是闰年,因此减少了一次错误的可能性):好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 | public static int NumLeapYearsToStartOfYear(int year) { if (year < YearZero) { throw new ArgumentException($"Only Years from {YearZero} onwards can be evaluated"); } //do it brute force int count = 0; for (var y = YearZero; y <= year; ++y) { if (IsLeapYear(y)) { ++count; } } return count; } |
有鉴于此,我可以计算出从"第0天"到利息年开始的天数:好的。
1 2 3 | public static int DaysToStartOfYear(int year) { return (year - YearZero) * 365 + NumLeapYearsToStartOfYear(year); } |
现在,切换档位,找出有趣的一天是什么"日数"(记住,2月3日是第34天)。好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public static int GetDayNumberFromDate (int year, int month, int day) { int[] daysPerMonth = IsLeapYear(year) ? _leapYearDaysPerMonth : _normalYearDaysPerMonth; if (month < 1 || month > 12) { throw new ArgumentException($"Month number ({month}) is invalid"); } if (day < 1 || day > daysPerMonth[month - 1]) { throw new ArgumentException($"Day/Month combination invalid for month:{month}, day:{day}"); } int dayCount = 0; for (int i = 0; i < month - 1; ++i) { dayCount += daysPerMonth[i]; } return dayCount + day; } |
最后把它们放在一起。正如您可能想象的那样,这段代码中有一个逐项的问题。我使用日期的"日数",它在1…n范围内,我们真的希望它是0…n-1。所以,我减去1。好的。
1 2 3 4 | public static DayOfWeek GetDayOfWeekFromDate (int year, int month, int day) { int totalDays = DaysToStartOfYear(year) + GetDayNumberFromDate(year, month, day) - 1 + (int)_day0; return (DayOfWeek)(totalDays % 7); } |
如果调用该函数,然后对结果调用
请不要将此作为您的工作提交。把它拆开,看看你能不能做得更好。如果您知道如何编写单元测试,请为每个函数编写一个测试(我通常会这样做,但不是今晚)。我向你展示了我展示给你的函数,按照我展示它们的顺序。为什么我要在我做的地方而不是在任何地方检查论点?我为什么要用
最后,您应该能够解释每一行代码。好的。好啊。
您可以采用的一种方法是计算从年初到指定日期的总天数,将该天数除以
首先,我们将在输入的月份之前添加每个月的总天数。要做到这一点,我们首先需要找出他们输入的月份,然后将其转换为一个整数,我们可以将其用作
我们首先可以通过使用
1 |
使用此值,我们可以循环访问此月之前的每个月,并添加截至此月的总天数:
1 2 3 4 | for (int i = 0; i < monthNumber; i++) { daysFromStartOfYear += daysInEachMonth[i]; } |
接下来,我们将加上他们输入的月份的第几天并减去1(我们需要减去一个,因为我们处理的是数组索引和
1 | daysFromStartOfYear += dayDate - 1; |
现在,我们需要通过增加一年中第一天的数值(其中
1 2 | Day firstDayOfYear = Day.Friday; daysFromStartOfYear += (int) firstDayOfYear; |
现在剩下要做的就是将这个数字除以
为了得到一个数除以另一个数的余数,我们可以使用模运算符
1 | int remainder = daysFromStartOfYear % numDaysInWeek; |
当我们得到这个数字时,我们可以将它强制转换为枚举以获取值:
1 | Day answer = (Day) remainder; |
希望这足以让你开始。尝试一下,如果你在某些特定的事情上遇到困难,或者在下面的评论中随意提问,就回来。
现在我了解到你的任务完全集中在2016年作为一年,你的简报要求你使用嵌套循环,以及你提供的代码,我建议你这样做:
1)定义targetmonth和targetmate(例如9月、3日)2)确保星期五开始3)使用此伪代码:
1 2 3 4 5 6 7 | foreach mMonth in Months for dayOfM = 1 to daysinMonth[month] (inclusive) if month == targetMonth AND dayOfM == targetDate print dayOfWeek return else dayOfWeek = (dayOfWeek + 1) % 7 |
有用功能:
Enum.GetValues(typeof(Months)) 将以数组形式返回Months 中的所有值。.OfType (包括() using System.Linq 命名空间)-您可以使用它将Enum.GetValues() 返回的Array 转换为强类型Months 对象。- 您可以使用
(int)dayofWeek 将dayOfWeek 转换为整数,然后使用(Days)5 返回(或您拥有的任何整数值)。 - 模量
% 将返回计算的其余部分。1%7=1,2%7=2,…,7%7==0-这将允许您循环一周中的几天。
这是我在C语言中提出的解决方案,并重新使用了伪代码,以便不向您提供一个可复制/可复制的答案。希望有帮助。
如果您只想显示一周中的某一天,可以这样做:
1 2 | DateTime date = new DateTime(2016, 1, 16); Console.WriteLine(dateValue.ToString("dddd")); // outputs Friday |