【问题标题】:Order date list for comparison用于比较的订单日期列表
【发布时间】:2019-02-04 10:15:33
【问题描述】:

我之前在这里问过这个问题:List of Dates ordered in a certain way

我认为建议的解决方案很好直到我的日期列表上的年份结束并遇到问题。

我的日期列表(采用这种基于字符串的格式 - 这就是数据从源 API 传给我的方式)

201711
201712
201801
201811
201812
201901

我想以条形图显示我的数据,以显示按月顺序显示 3 个月的年同比比较。这意味着我按顺序排列列表

201711
201811
201712
201812
201801
201901

然后我可以按顺序查看 11 月、12 月和 1 月的同比条形图。

我已经尝试了问题底部的解决方案,但它的顺序是这样的(这不是我想要的):

201801
201901
201711
201811
201712
201812

为了清楚起见,下个月它需要向前推进成为这个日期列表:

我想要的第一个月总是比当前月份早 2 个月

201712
201812
201801
201901
201802
201902

var rowsInOrder = dateList.OrderBy(n => DateTime.ParseExact(n, "yyyyMM", CultureInfo.CurrentCulture).Month).ThenBy(n=> DateTime.ParseExact(n, "yyyyMM", CultureInfo.CurrentCulture).Year);

【问题讨论】:

  • @LuckyLikey 日期来自字符串格式的 API。我需要重新排序上述数据以呈现我需要的方式
  • @mjwills 我已经添加了下个月列表的外观。谢谢你的提示。我会试一试的!
  • @mjwills - 是的,它总是按时间顺序排列。我需要重新安排它以满足我的比较要求。

标签: c# arrays list linq datetime


【解决方案1】:

您可以使用首先确定月份组的查找方法:

var monthLookup = dateList
    .Select(s => new{String = s, Date = DateTime.ParseExact(s, "yyyyMM", CultureInfo.CurrentCulture)})
    .OrderBy(x => x.Date)  // not necessary in your sample data but i assume it's desired
    .ToLookup(x=> x.Date.Month);
var rowsInOrder = monthLookup.SelectMany(x => x).Select(x => x.String);

【讨论】:

  • @Rango 这对我来说看起来不错。谢谢你。自我注意 - 阅读ToLookup
  • 所以您将始终获得前几年的结果,您还可以对不使用的项目进行分组和订购,每个组都包含您想要的更多年份?
  • @HaraldCoppoolse:如果需要,您可以轻松添加DateTime-filter:dateList.Select(same).Where(x => x.Date >= minDate && y.Date <= maxDate).OrderBy(same).ToLookup(same)
  • 不是那么容易:他想要几个组的酒吧,每组包含一年中的几个月。例如,2018 年,从第 11 个月开始,3 个月,4 年。所以组十一月:2018-11、2019-11、2020-11、2021-11。 12月组:2018-12、2019-12、2020-12、2021-12;组一月:2019-01、2020-01、2021-01、2022-01。所以没有 2021-08、2021-09,是的:2021-10
【解决方案2】:

我可以使用GroupBy 对月份进行分组来实现您的目标,

var rowsInOrder = new List<string>();
foreach (var grouping in dates.GroupBy(s =>
        DateTime.ParseExact(s, "yyyyMM", CultureInfo.CurrentCulture).Month))
{
    rowsInOrder.AddRange(grouping.OrderBy(s => s));
};

你也可以用同样的逻辑来排序月份:

var rowsInOrder = new List<string>();
foreach (var grouping in dates
    .OrderBy(s => DateTime.ParseExact(s, "yyyyMM", CultureInfo.CurrentCulture).Month).GroupBy(s =>
        DateTime.ParseExact(s, "yyyyMM", CultureInfo.CurrentCulture).Month))
{
    rowsInOrder.AddRange(grouping.OrderBy(s => s));
}

【讨论】:

    【解决方案3】:

    在我看来这就足够了:

    var rowsInOrder = dates.OrderBy(x => x).GroupBy(x => x.Substring(4)).SelectMany(x => x);
    

    根本没有必要胡乱解析日期。这是一个简单的字符串排序和分组方式。

    【讨论】:

      【解决方案4】:

      所以你被一系列对象困住了,其中每个对象都有一个类型为 string 的 Date 属性,格式为 yyyyMM。并且您想从中提取一些数据。

      您的日期格式与语言无关。不管你的电脑是英国的还是中国的。 Date 属性将始终采用 yyyyMM 格式。

      这使得将其转换为 DateTime 格式变得相当容易,从而可以轻松访问年份和月份。

      const string dateTimeFormat = "yyyyMM";
      CultureInfo provider = CultureInfo.InvariantCulture;
      var dateList = ...      // your original list of items with the string Date property
      
      var itemsWithYearMonth = dateList.Select(item => new
      {
          DateTime = DateTime.ParseExact(item, dateTimeFormat, provider)
          ... // select other items you need for your bar chart
      });
      

      现在,给定一个 StartYear/Month、一个 NrOfYears 和一个 NrOfMonths,您希望将 dateTimeItems 分组到同一月份的组中。

      例如,从 2018-11 年开始,我想要四个月的小组,连续三年(是的,是的,我知道在你最初的要求中只有 3 个月、2 年,但为什么要限制自己,让我们让您的代码可重用):

      group 1: 2018-11, 2019-11, 2020-11, 2021-11
      group 2: 2018-12, 2019-12, 2020-12, 2021-12
      group 3: 2019-01, 2020-01, 2021-01, 2022-01
      

      奖励积分:我们将通过年限!

      所以输入:

      var itemsWithYearMonth = ... // see above
      int startYear = ...
      int startMonth = ...
      int nrOfMonths = ...    
      int nrOfYears = ...
      

      我们将制作具有相同月份的物品组。我们不想要一年中的所有月份,我们只想要几个月。如果我们想要从第 11 个月开始的 3 个月,我们需要保留第 11、12、1 个月的组。

      var desiredMonths = Enumerable.Range(startMonth, nrOfMonths)   // example: 11, 12, 13
          .Select(monthNr => 1 + ((monthNr-1) % 12));                // 11, 12, 1
      

      根据您的输入,我们不想要所有月份,我们只想要比起始月份大的年/月。

      DateTime startMonth = new DateTime(startYear, startMonth, 1);
      

      最简单的方法是只保留日期等于或大于 startMonth 的项目的输入源,并且只取每个组的第一个 NumberOfYears 项目。这样,如果您像我在示例中所做的那样通过年份边界,您将获得正确数量的项目。

      var result = itemsWithYearMonth
          // keep only the items newer than startMonth
          .Where(item => item.DateTime >= startMonth)
      
          // group by same month:
          .GroupBy(item => item.DateTime.Month,
          (month, itemsWithThisMonth) => new
          {
              Month = month,        // in my example: 11, 12, 1, ...
      
              // in every group: take the first nrOfYears items:
              Items = itemsWithThisMonth
                      // order by ascending year
                      .OrderBy(itemWithThisMonth => itemWithThisMonth.Year)
                      // no need to order by Month, all Months are equal in this group
                      .Take(nrOfYears)
                      .ToList(),
           })
           // keep only the desired months:
           .Select(group => desiredMonth.Contains(group.Month));
      

      所以现在你有了组:

      group of month 11, with data of years 2018, 2019, 2020, 2021
      group of month 12, with data of years 2018, 2019, 2020, 2021
      group of month 01, with data of years 2019, 2020, 2021, 2022
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-30
        • 1970-01-01
        • 2014-06-25
        相关资源
        最近更新 更多