我有一个C#列表项目如下 -
List<MyClass> All_Items = GetListItems();
GetListItems()
返回结果如下 -
Category StartDate EndDate
AA 2008-05-1
AA 2012-02-1
BB 2009-09-1
BB 2010-08-1
CC 2009-10-1
在All_Items
上使用LINQ,我希望以如下方式更新EndDate列
最终结果如下 -
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
我只能想到使用太多循环来完成它。什么是更好的选择?
答案 0 :(得分:2)
您可以为每个类别选择日期并将其放入字典中以便以后节省时间。
然后,根据您的要求,您只需检查所有项目并检查开始日期是否小于下一类。
这是:
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;
}
答案 1 :(得分:2)
试试这段代码。它遍历所有项目并选择下一个更大的项目.StartDate为同一类别。 如果此类项目不可用,则会设置默认日期。
我无法测试代码,因为我正在手机上书写,因此欢迎任何更正。
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);
}
答案 2 :(得分:2)
LINQ不适合处理序列元素之间的依赖关系,并且肯定不用于更新。
以下是实现目标的简单有效方法:
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来按StartDate
对元素进行排序,并将结果分组为Category
(这样可以保留每个组内的排序)。然后简单地迭代LINQ查询结果并相应地更新EndDate
。
答案 3 :(得分:1)
让我们假设您的MyClass
看起来像这样:
public class MyClass
{
public string Category { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
以下是如何操作的方法,请参阅代码中的注释以获得解释。
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
};
});
});
答案 4 :(得分:1)
在单个LINQ语句中(maxEndDate
为2099-12-31):
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);