【问题标题】:Is there a better solution to this List<DateTime> sorting?这个 List<DateTime> 排序有更好的解决方案吗?
【发布时间】:2011-07-01 20:37:59
【问题描述】:

我正在为 ASP.NET MVC 菜单编写一个类。我希望能够获取所有博客条目的列表并制作一个类似于此的存档菜单:

1/2011 (2)
3/2011 (1)
4/2011 (12)
etc...

这是我正在使用的代码:

public class ArchiveMenuModel
{
    private List<ArchiveMenuItem> menuItems;
    public List<ArchiveMenuItem> MenuItems { get { return menuItems; } }

    public ArchiveMenuModel(List<DateTime> dates, string streamUrl)
    {
        menuItems = new List<ArchiveMenuItem>();
        int itemCount = 0;
        dates = dates.OrderByDescending(x => x).ToList();

        for (int i=0; i<dates.Count; i++)
        {
            itemCount++;
            if(i+1 < dates.Count)
            {
                if(!(dates[i].Month == dates[i + 1].Month && dates[i].Year == dates[i + 1].Year))
                {
                    menuItems.Add(new ArchiveMenuItem(streamUrl, dates[i].Month, dates[i].Year, itemCount));
                    itemCount = 0;
                }
            }
            else
            {
                menuItems.Add(new ArchiveMenuItem(streamUrl, dates[i].Month, dates[i].Year, itemCount));
            }
        }

    }
}

有没有更好的方法,也许是使用 Linq 之类的?具体来说,我不喜欢的代码部分是:

if(!(dates[i].Month == dates[i + 1].Month && dates[i].Year == dates[i + 1].Year))

如果我能避免这样丑陋的 if 语句,那就太好了!

【问题讨论】:

  • 里面有 LINQ 吗? ;-) 参见IEnumerable 中的OrderByGroupBy。后者将获得您的组(然后可以计算每个组中的元素),前者将获得有序的组。用“花哨的 LINQ 语法”装饰......或保留正常的方法调用(我的首选方式)。这不是一个答案,因为我只是不想写下任何代码——在LINQPad 玩一会儿,享受吧!
  • 当我尝试这样做时,我无法获得条目计数。另外,GroupBy 是否能够按月+年而不是时间返回 DateTime 组?
  • 是否要包括空月份? IE。像“5/2011 (0)”这样的行?
  • @svick - 我在想我不会包括空月。找不到充分的理由……至少现在还没有;-)

标签: c# asp.net-mvc linq sorting


【解决方案1】:
menuItems = dates
     .GroupBy(x => new DateTime(x.Year, x.Month, 1))
     .Select(x=> new{Date = x.Key, Count = x.Count()})
     .OrderByDescending(x => x.Date)
     .Select(x => new ArchiveMenuItem(streamUrl, 
                                      x.Date.Month, 
                                      x.Date.Year, 
                                      x.Count))
     .ToList();

【讨论】:

    【解决方案2】:
    var menuItems = from date in dates
                    group date by new { date.Year, date.Month } into g
                    select new { g.Key.Year, g.Key.Month, Count = g.Count() } into month
                    orderby month.Year, month.Month
                    select new ArchiveMenuItem(streamUrl, month.Month, month.Year, month.Count);
    

    这个 LINQ 查询

    1. 按年和月对日期进行分组
    2. 为每个组选择年、月和日期数
    3. 按年和月对组进行排序
    4. 为每个组创建ArchiveMenuItem

    【讨论】:

    • 感谢您的补充说明。看起来你和 Handrcraftsman 基本上是在做同样的事情。
    • @quakkels,是的,基本一样。
    【解决方案3】:
    var memuItems = dates.Select(o => o.Date.AddDays(-o.Date.Day + 1))
                .GroupBy(o => o, (o, p) => new {MonthAndYear = o.Date, EntriesCount = p.Count()})
                .Select(o => new ArchiveMenuItem(streamUrl, o.MonthAndYear.Month, o.MonthAndYear.Year, o.EntriesCount));
    

    我减去天数得到日期(到月初),所以我可以使用年和月进行分组。

    【讨论】:

      【解决方案4】:

      @svick 和 @danyolgiax,

      这是我从 dany 的链接中得出的:

      public class ArchiveMenuModel
      {
          private List<ArchiveMenuItem> menuItems;
          public List<ArchiveMenuItem> MenuItems { get { return menuItems; } }
      
          public ArchiveMenuModel(List<DateTime> dates, string streamUrl)
          {
              menuItems = new List<ArchiveMenuItem>();
              dates = dates.OrderByDescending(x => x).ToList();
      
              var grouped = from d in dates
                              group d by new { month = d.Month, year= d.Year } into d     
                              select new { dt = d, count = d.Count() };
              foreach(var item in grouped)
              {
                  menuItems.Add(new ArchiveMenuItem(streamUrl, item.dt.Key.month, item.dt.Key.year, item.count));
              }
          }
      }
      

      【讨论】:

        【解决方案5】:

        按照这些思路应该可以工作:

          menuItems.GroupBy(x => x.Month + "/" + x.Year);
        

        我不知道保存 DateTime 的属性的名称,但它必须像这样设置,

          menuItems.GroupBy(x => x.(datetime).Month + "/" + x.(datetime).Year); 
        

        【讨论】:

        • 你为什么要创建一个字符串来做到这一点?
        • 分组工作正常。我不清楚 DateTimes 列表中到底应该包含什么。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-08
        • 2011-10-18
        • 1970-01-01
        • 2010-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多