2013-07-11 37 views
0

我有一个日历事件对象的集合,其日期值跨越多个学年,即201213 201112等 我需要首先将对象按年分组,因为集合上的第一个枚举基于学年。然后我需要按月分组日期。 (月份也需要从当前日期后退,然后月份分组中的每个日期都需要按照从最新到最早的顺序递减字典词典是最好的解决方案吗?

因此,我正在与自己讨论如何做到这一点的最佳方式,我想到每年都有一个学年的关键,它指向一个词典集合的价值,这个词典的集合又有一个月的关键词,然后是一个日历事件对象集合。

dictionary<string, dictionary<string, List<CalendarEvent>>

我对这种方法的一个担心是排序和确保正确的顺序维护,因为这些对象将用于创建时间线,whe重新在时间轴上的第一个对象是最新的。 (以facebook时间线为例,其中facebook事件按年,月和周等分组)。

上述集合是最好的,还是有更简单的解决方案或路径我可以下去,我可能没有考虑过?

这个集合将被传递给一个MVC视图,所以视图中集合的按摩越少越好,这就是为什么我没有走下List的路径,日期也按照学术跨越九月至六月的一年,因此学年为字符串“201213”。所以我的意图是循环一次通过集合。

我打算循环一次通过词典和字典循环中的每个项目再次通过月的内部字典然后通过实际的日历对象循环再次为我提供时间线的事件按时间顺序降序。

随着降

即事件......

--event 1 7月10日

- 事件2 7月1日

六月

- 事件X 6月30日

- 事件foo的6月1日

- 事件条4月1日

+0

请定义“更好”可以回答这个问题。请注意,您目前的方法明显处于“坏”的一面,因为您似乎正在使用字符串作为数字数据(年份通常是“int”,而不是“字符串”)。 –

+1

这完全取决于你将如何使用这些对象。您可以将它们放在一个直式列表中,并在需要时随时用LINQ进行分组/排序。不知道你的使用模式是什么,这个问题不是很有意义。 – Jon

+0

我与Jon共享相同的想法,列表或类似可能已足够用LINQ的orderby等 – Sayse

回答

2

对我来说,似乎你已经结束了复杂的问题。如果你只是说了几十年的有价值的数据,你可以只使用一个List<CalendarEvent>二维数组:

const int NumYears = 100; 
const int BaseYear = 2012; 
List<CalendarEvent>[,] MyEvents = new List<CalendarEvent>[NumYears, 12]; 

因此,要获得该列表为2014年1月,你可以这样写:

List<CalendarEvent> jan2014 = MyEvents[2014 - BaseYear, 0]; 

这并不占用大量的空间,而且使用起来非常简单。阵列本身只需要100*12*(sizeof IntPtr)字节。因此,32位机器上的大约4,800个字节或64位机器上的9,600个字节。您分配的每个列表当然需要更多的空间,但是如果某个月没有事件发生,那么您不必支付该成本。如果大多数月份都有事件发生,这将比字典占用更少的空间。

如果你的学年是9月到6月,你担心太空,你可以让第二个等级只有10个元素,并有方法将你的月份/年份(比如2014年1月)转换为正确的索引(我认为这将是2013学年的第4个月)。不过,我可能不会担心。我们只谈及200年的空值参考资料。它可能需要更多的代码才能表达特殊情况。

就个人事件而言,在某个月可能并不是很多,所以按照时间顺序排列并不合理。只需在列表上按日期排序OrderBy,以便列举它们。对少量事件进行排序不会花费任何可观的时间。

它应该很容易包装在一个实现IEnumerable<CalendarEvent>并保证正确的枚举顺序的类中。

另一种选择是使用简单的List<CalendarEvent>作为后备存储,并以任意顺序将事件放入其中。然后,如果您想显示特定学年或一系列年份(甚至是单个月份或日期)的所有事件,则可以使用LINQ选择并按(降序?)排序以挑选出您想要的。这实际上取决于多少事件,总数,您正在使用的以及您需要多久进行一次按摩。如果事件的总数是几千甚至几万,那么选择和排序将花费毫秒。如果数字和我猜想的一样小,这可能就是我的选择。

+0

谢谢吉姆我会给它一个旋转,我希望我提出的解决方案是错综复杂的。 –

+1

这是一种让我喜欢StackOverflow的评论。让不同的大脑考虑一个策略和现实 - 为你检查它是非常有价值的。这是一个很好的分析,并有可能为OPer节省很多工作和痛苦。做得好。 – Curt

+0

@MikeRayner:查看我的更新。一个简单的'List '可能是要走的路。 –

0

字典不能保证枚举任何特定的顺序。 SortedList或SortedDictionary集合的树可能会做你想做的事情。

也许你应该使用支持IComparable的集合(如List)。

+0

您可以在字典上使用'OrderBy',然后枚举它将按照您指定的顺序进行。 – aevitas

+0

只能通过Linq。 – Curt

+0

只能通过Linq?只要首先对字典进行排序,就可以按照特定的顺序使用'foreach'来枚举它。 – aevitas

0

A range tree,以时间为关键点,可能是一个更好的主意。这里是关于他们的some helpful slides

范围树需要很少的家务管理,因为树唯一关心的是确切的时间。它独立于人类的构造,如月和年,这很好,因为人类的构造是可怕的可怕事物(例如,由于时区,月份实际上在许多不同的时间结束)。只有在确定要查询的范围时,人的东西才会进入画面。

0

您应该尝试这个易于实施和维护的解决方案;使用:

SortedDictionary<YearMonth, Event> 

的YearMonth类应该实现IComparable,在那里你可以指定年,月有一个从大到小的顺序。

干杯

+0

这看起来更有利,我没有考虑可以同时使用年份和月份来获得我需要的钥匙。我会试试看看它是否提供了我需要的结果。 –

0

由于每个事件都会有你创建的每个用适当的和事件描述的日期,我做了便于显示calendarevent类和月份枚举:

public enum NameOfMonth 
    { 
     january = 1, 
     febuary, 
     march, 
     april, 
     may, 
     june, 
     july, 
     august, 
     september, 
     october, 
     november, 
     december 
    } 

    class CalendarEvent 
    { 
     public NameOfMonth month; 
     public DateTime date { get; set; } 
     public string eventdescription { get; set; } 

     public CalendarEvent() 
     { 

     } 
    } 

然后创建与每个calendarevent对象名单(每一个当然有一个描述,日期,等等......),然后按年创建一个匿名对象并按月排序,然后按天显示它们:

  List<CalendarEvent> myevents = new List<CalendarEvent>() 
      { 
       new CalendarEvent(){date = new DateTime(2005,1,17),eventdescription = "Armaggedon",month = NameOfMonth.january}, 
       new CalendarEvent(){date = new DateTime(2005,3,20),eventdescription = "Apocalypse",month = NameOfMonth.march}, 
       new CalendarEvent(){date = new DateTime(2007,5,20),eventdescription = "WorldPeace",month = NameOfMonth.may}, 
       new CalendarEvent(){date = new DateTime(2009,2,20),eventdescription = "LaundryDay",month = NameOfMonth.febuary}, 
       new CalendarEvent(){date = new DateTime(2009,4,15),eventdescription = "MentalHealth",month = NameOfMonth.april}, 
       new CalendarEvent(){date = new DateTime(2009,6,10),eventdescription = "ProgrammingInC#",month = NameOfMonth.june}, 
       new CalendarEvent(){date = new DateTime(2009,6,12),eventdescription = "EraseAllYourWork?",month = NameOfMonth.june}, 
       new CalendarEvent(){date = new DateTime(2010,10,20),eventdescription = "SomeVeryNiceEvent",month = NameOfMonth.october}, 
       new CalendarEvent(){date = new DateTime(2010,8,21),eventdescription = "WellAnotherEvent",month = NameOfMonth.august} 
      }; 
      var result = myevents2.GroupBy(d => d.date.Year) 
         .Select(g => new { Year = g.Key, data = g.OrderByDescending(k => k.date.Month).ThenByDescending(day => day.date.Day) }) 
         .ToList(); 

      foreach (var item in result) 
      { 
       Console.WriteLine("Events on ***" + item.Year + "***"); 
       foreach (var subitems in item.data) 
       { 
        Console.WriteLine(subitems.month.ToString()); 
        Console.WriteLine("On day " + subitems.date.Day + " - " + subitems.eventdescription); 
       } 
      }