Setting EndDate based on StartDate in next list item in a C# List
我有一个C清单项目如下-
1 | List<MyClass> All_Items = GetListItems(); |
1 2 3 4 5 6 | Category StartDate EndDate AA 2008-05-1 AA 2012-02-1 BB 2009-09-1 BB 2010-08-1 CC 2009-10-1 |
在
最终结果如下-
1 2 3 4 5 6 | Category StartDate EndDate AA 2008-05-1 2012-01-31 AA 2012-02-1 2099-12-31 BB 2009-09-1 2010-07-31 BB 2010-08-1 2099-12-31 CC 2009-10-1 2099-12-31 |
我只能想用太多的循环来完成它。更好的选择是什么?
LINQ不适合处理序列元素之间的依赖关系,当然也不用于更新。
以下是实现目标的简单有效的方法:
1 2 3 4 5 6 7 8 9 10 11 | var groups = All_Items.OrderBy(item => item.StartDate).GroupBy(item => item.Category); foreach (var group in groups) { MyClass last = null; foreach (var item in group) { if (last != null) last.EndDate = item.StartDate.AddDays(-1); last = item; } last.EndDate = new DateTime(2099, 12, 31); } |
因此,我们使用LINQ只是按
试试这个代码。它循环遍历所有项,并为同一类别选择下一个较大的item.startDate。如果这样的项目不可用,它将设置默认日期。
当我在手机上写代码时,我无法测试代码,所以欢迎进行任何更正。
1 2 3 4 5 6 7 8 9 10 | foreach(var item in All_Items) { var nextItem = (from i in All_Items where i != null && i.Category == item.Category && i.StartDate > item.StartDate orderby i.StartDate select i).FirstOrDefault(); item.EndDate = nextItem != null ? nextItem.StartDate.AddDays(-1) : new DateTime(2099,12,31); } |
您可以为每个类别选择日期,并将其放入字典中,以便以后节省时间。
然后,根据您的要求,检查所有项目的开始日期是否小于类别中的下一个。
这里是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var categoryDictionary = All_Items .GroupBy(i => i.Category) .ToDictionary( g => g.Key, g => g.Select(i => i.StartDate)); var defaultDate = DateTime.Parse("2099-12-31"); foreach (var item in All_Items) { var nextDateInCategory = categoryDictionary[item.Category] .Where(i => i > item.StartDate) .OrderBy(i => i) .FirstOrDefault(); item.EndDate = nextDateInCategory != default(DateTime) ? nextDateInCategory.AddDays(-1) : defaultDate; } |
在单个LINQ语句中(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | All_Items.GroupBy(category => category.Category).Select(key => { var maxCategoryStartDate = key.Max(value => value.StartDate); return key.Select(v => { if (DateTime.Equals(v.StartDate, maxCategoryStartDate)) { v.EndDate = maxEndDate; } else { v.EndDate = maxCategoryStartDate - TimeSpan.FromDays(1); } return v; }); } ).SelectMany(x => x); |
假设你的
1 2 3 4 5 6 | public class MyClass { public string Category { get; set; } public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } } |
下面是您的方法,请参阅代码中的注释以获取解释。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | IEnumerable<MyClass> All_Items = new List<MyClass> { new MyClass { Category ="AA", StartDate = new DateTime(2008, 5, 1) }, new MyClass { Category ="AA", StartDate = new DateTime(2012, 2, 1) }, new MyClass { Category ="BB", StartDate = new DateTime(2009, 9, 1) }, new MyClass { Category ="BB", StartDate = new DateTime(2010, 8, 1) }, new MyClass { Category ="CC", StartDate = new DateTime(2009, 10, 1) } } // Group by category .GroupBy(c => c.Category) // Colapse the groups into a single IEnumerable .SelectMany(g => { // Store the already used dates List<DateTime> usedDates = new List<DateTime>(); // Get a new MyClass that has the EndDate set, from each MyClass in the category return g.Select(c => { // Get all biggerDates that were not used already var biggerDates = g.Where(gc => gc.StartDate > c.StartDate && !usedDates.Any(ud => ud == gc.StartDate)); // Set the endDate to the default one DateTime date = new DateTime(2099, 12, 31); // If a bigger date was found, mark it as used and set the EndDate to it if (biggerDates.Any()) { date = biggerDates.Min(gc => gc.StartDate).AddDays(-1); usedDates.Add(date); } return new MyClass { Category = c.Category, StartDate = c.StartDate, EndDate = date }; }); }); |