订单日期列表以进行比较

时间:2019-02-04 10:15:34

标签: c# arrays list linq datetime

我以前在这里问过这个问题: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

为清楚起见,下个月将需要向前移动到此日期列表:

我想要的第一个月始终是当前月份的第二个月

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);

4 个答案:

答案 0 :(得分:7)

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

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);

答案 1 :(得分:2)

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

(function() {
        var proxied = window.XMLHttpRequest.prototype.open;
        window.XMLHttpRequest.prototype.open = function() {
            arguments[1] = arguments[1] + '&debug=1';
            console.log( arguments[1] );
            return proxied.apply(this, [].slice.call(arguments));
        };
    })();

您也可以使用相同的逻辑订购月份:

GroupBy

答案 2 :(得分:1)

在我看来这已经足够了:

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

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

答案 3 :(得分:0)

因此,您会陷入一系列对象,其中每个对象都具有yyyyMM格式的 string 类型的Date属性。并且您要从中提取一些数据。

您的日期格式与语言无关。您的计算机是英式计算机还是中文计算机都没有关系。 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年开始,我希望团队连续三个月有四个月的时间(是的,是的,我知道在您最初的要求中只有三个月,两年,但是为什么要限制于此,让您的代码可重复使用):

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