用更好的方法填充一个二维数组,其中包含日期和星座。

4
我正在处理以下问题:
我想填充一个二维[365,2]数组。第一个值应该保存日期:从1月1日开始到12月31日结束。第二个值应该保存每个日期对应的星座。
例如,array [0,0]保存101,array [0,1]保存白羊座等。
我编写了一个函数:
public static void fill_array(string[,] year_zodiac, int days, string zodiac, string startdate, int starting_day) 
{
    //function to fill array with date and zodiac
    int startdate_int = 0;
    for (int i = starting_day; i <= days; i++)
    {
        year_zodiac[i, 0] = startdate;
        year_zodiac[i, 1] = zodiac;

        startdate_int = Int32.Parse(startdate);
        startdate_int++;
        startdate = startdate_int.ToString();
    }

然后像这样调用它:

fill_array(main_array, 18, "Aries", "101", 0);

必须为每个星座都执行此操作。我通过简单地两次调用fill_array(即,一次为12月份白羊座的部分调用它,一次为1月份白羊座的部分调用)来绕过月份间隔问题。

这个解决方案可行,但对我来说似乎太粗糙了。

有人能给我指出更优雅的解决方案吗?


3
你的初始问题是什么?也就是说,你为什么要填充这个数组?看起来你可能正在过度复杂化它。 - K893824
我确实在过度复杂化我的原始问题 :), 但我仍然想知道如何有效地处理它。 - Fang
不,完全不是。事实上(因为我是初学者),这个练习本应该只需要用几个简单的if语句就能解决,但我对那个解决方案并不满意。 - Fang
目前这个问题被“搁置”了,因为我以前从未处理过枚举,并且必须彻底分析代码(因此我无法评估给出的答案有多好)。尽管如此,我现在想先感谢你们两位。 - Fang
您可以查看此答案中的BirthdayToZodiacSign方法:http://stackoverflow.com/a/22603915/1803777 - Ulugbek Umirov
显示剩余4条评论
2个回答

11

这里有一个能够满足你要求的类,已经过测试。在第一个示例中,我没有填写所有标志,但在重构后我完善了它们。建议你进行充分的测试,因为我只测试了一些案例,可能会错过一些边缘情况。

正如@ClickRick指出的那样,我起初使用了他的数组/枚举设计,但发现在使用Linq时不太适用,于是转而使用List。我也不得不修复他的数据数组以使其编译通过。我按照应有的方式给予了他相应的功劳。

public class Signs
{
   static List<string> SignList = new List<string>() {  "Aquarius", "Pisces", "Aries", "Taurus", "Not Found"};

   static DateTime[] startDates =  {
        new DateTime(DateTime.Now.Year,1,21),
        new DateTime(DateTime.Now.Year,2,20),
        new DateTime(DateTime.Now.Year,3,21),
        new DateTime(DateTime.Now.Year,4,21),
        new DateTime(DateTime.Now.Year,12,31)  };

    static public string Sign(DateTime inDate)
    {
       return SignList.Zip(startDates, (s, d) => new { sign = s, date = d })
                      .Where(x => (inDate.Month*100)+inDate.Day <= (x.date.Month*100)+x.date.Day)
                      .Select(x => x.sign)
                      .First();
    }
}

重构(在上面的例子中更清晰明了)

public class Signs
{
  static List<string> SignList = new List<string>() {
    "Capricorn", "Aquarius", "Pisces", "Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo", "Libra", "Scorpio", "Sagittarius", "Capricorn", "Not Found" };

  static List<int> startDates = new List<int>() {
    // month * 100 + day of month
     120, 219, 320, 420, 521, 621, 722, 821, 923, 1023, 1122, 1222, 1232, 9999 // edge marker
  };

  static public string Sign(DateTime inDate)
  {
    return SignList[startDates.TakeWhile(d => (inDate.Month*100)+inDate.Day > d).Count()];
  }
}

8

为什么您特别需要一个数组?更复杂的数据结构可以更好地封装功能,并帮助您将剩余代码与其工作方式隔离开来。此外,如果将来要考虑日期的微妙变化,这也会让您更容易处理。

例如:

public class SO23182879
{
    public enum StarSign
    {
        Aquarius, Pisces, Aries, Taurus, Gemini, Cancer,
        Leo, Virgo, Libra, Scorpio, Sagittarius, Capricorn
    };
    static DateTime[] starSignStartDates = new DateTime[]
    {
        new DateTime(DateTime.Now.Year, 1, 20),
        new DateTime(DateTime.Now.Year, 2, 19),
        new DateTime(DateTime.Now.Year, 3, 21),
        new DateTime(DateTime.Now.Year, 4, 20),
        new DateTime(DateTime.Now.Year, 5, 21),
        new DateTime(DateTime.Now.Year, 6, 21),
        new DateTime(DateTime.Now.Year, 7, 23),
        new DateTime(DateTime.Now.Year, 8, 23),
        new DateTime(DateTime.Now.Year, 9, 23),
        new DateTime(DateTime.Now.Year, 10, 23),
        new DateTime(DateTime.Now.Year, 11, 22),
        new DateTime(DateTime.Now.Year, 12, 22),
        new DateTime(DateTime.Now.Year, 1, 20),
    };
    private class StarSignDateRange
    {
        public StarSign Sign { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
    }
    private List<StarSignDateRange> signStartDates = new List<StarSignDateRange>();

    public SO23182879()
    {
        int date = 0;
        foreach (StarSign sign in Enum.GetValues(typeof(StarSign)))
        {
            signStartDates.Add(new StarSignDateRange
            {
                Sign = sign,
                StartDate = starSignStartDates[date],
                EndDate = starSignStartDates[date + 1]
            });
            ++date;
        }
    }

    public StarSign Sign(DateTime date)
    {
        return signStartDates.First(
            sd => date.Month == sd.StartDate.Month && date.Day >= sd.StartDate.Day ||
                  date.Month == sd.EndDate.Month && date.Day < sd.EndDate.Day
                                   ).Sign;
    }

    public void Test()
    {
        IList<DateTime> testDates = new List<DateTime>
        {
            new DateTime(2014,1,1),
            new DateTime(2014,1,19),
            new DateTime(2014,1,20),
            new DateTime(2014,4,19),
            new DateTime(2014,4,20),
            new DateTime(2014,12,21),
            new DateTime(2014,12,22),
            new DateTime(2014,12,31),
        };
        foreach (DateTime d in testDates)
            Console.WriteLine(string.Format("{0} is in {1}", d, Sign(d)));
    }
}

正如您所见,我已经完成了之前开始的代码,并添加了一个Test()方法让您看到边缘条件是如何工作的。感谢Hogan指出了我之前草图中存在的“零年”问题和其他类似的“坑点”。


是的,我写了那个并进行了一些谷歌搜索 - 我已经删除了它。很好的答案,我给你点赞了。 - Hogan
感谢您的努力!我会在本周晚些时候进行比较。 - Fang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接