从多个组中的每个组中选择一个项目
本文关键字:一个 项目 选择 | 更新日期: 2023-09-27 18:29:10
我有一个特定类别的项目列表(特别是IEnumerable):
internal class MyItem
{
public MyItem(DateTime timestamp, string code)
{
Timestamp= timestamp;
Code = code;
}
public DateTime Timestamp { get; private set; }
public string Code { get; private set; }
}
在此列表中,将有多个项目具有相同的代码。每个都有一个时间戳,可能是唯一的,也可能不是唯一的。
我正在尝试检索MyItem(Dictionary<string, MyItem>
)的字典,其中键是与该项关联的代码。
public Dictionary<string, MyItem> GetLatestCodes(IEnumerable<MyItem> items, DateTime latestAllowableTimestamp)
给定这个签名,我如何为每个代码检索时间戳最接近但不在latestAllowableTimestamp
之后的MyItem
?
例如,给定以下输入:
IEnumerable<MyItem> items = new List<MyItem>{
new MyItem(DateTime.Parse("1/1/2014"), "1"),
new MyItem(DateTime.Parse("1/2/2014"), "2"),
new MyItem(DateTime.Parse("1/3/2014"), "1"),
new MyItem(DateTime.Parse("1/4/2014"), "1"),
new MyItem(DateTime.Parse("1/4/2014"), "2")};
如果latestAllowableTimestamp
是2014年1月3日,则结果将仅包含以下项目:
Timestamp | Code
----------------
1/3/2014 | 1
1/2/2014 | 2
我可以设法将列表筛选到latestAllowableTimestamp
之前的时间戳,但我对linq的了解还不够好,无法为每个代码选择最新的代码并将其插入词典。
var output = items.Where(t => (t.Timestamp <= latestAllowableTimestamp)).GroupBy(t => t.Code);
在这一点上,我最终得到了两组,但不知道如何在每组中选择一个项目。
这是您尝试编写的实际方法。它甚至返回一本字典和所有内容:
static Dictionary<string, MyItem> GetLatestCodes(
IEnumerable<MyItem> items, DateTime latestAllowableTimestamp)
{
return items
.Where(item => item.TimeStamp <= latestAllowableTimestamp)
.GroupBy(item => item.Code)
.Select(group => group
.OrderByDescending(item => item.TimeStamp)
.First())
.ToDictionary(item => item.Code);
}
请参阅枚举ToDictionary
这是你应该在问题中发布的部分(正如LB所指出的)
var list = new List<MyItem>()
{
new MyItem(){ code = "1" , timestamp = new DateTime(2014,1,1)},
new MyItem(){ code = "2" , timestamp = new DateTime(2014,1,2)},
new MyItem(){ code = "1" , timestamp = new DateTime(2014,1,3)},
new MyItem(){ code = "1" , timestamp = new DateTime(2014,1,4)},
new MyItem(){ code = "2" , timestamp = new DateTime(2014,1,4)}
};
DateTime latestAllowableTimestamp = new DateTime(2014, 1, 3);
这是我的答案
var result = list.GroupBy(x => x.code)
.Select(x => x.OrderByDescending(y => y.timestamp)
.FirstOrDefault(z => z.timestamp <= latestAllowableTimestamp))
.ToList();
要创建Dictionary,可以这样构造查询:
var newDict = items.Where(a => a.Timestamp <= latestAllowableTimestamp)
.GroupBy(b => b.Timestamp)
.ToDictionary(c => c.First().Timestamp, c => c.First());
这应该会根据您的数据创建一个字典,没有重复的天数。请注意,如果没有GroupBy
查询,您将引发一个异常,因为ToDictionary
不会过滤掉它已经看到的键。
然后,如果你想为任何给定的代码号只获得一个MyItem,你可以使用这个查询:
newDict.Select(a => a.Value)
.OrderByDescending(b => b.Timestamp)
.GroupBy(c => c.Code)
.Select(d => d.First());
FirstOrDefault
查询将只从每组中返回一个元素。这将为您提供最接近任何给定代码的最新日期的MyItem。