从多个组中的每个组中选择单个项目

时间:2014-11-04 18:17:16

标签: c# linq

我有一个特定类的项目列表(特别是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)

鉴于此签名,如何为每个代码检索最接近MyItem但不是latestAllowableTimestamp之后的时间戳的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

如果Timestamp | Code ---------------- 1/3/2014 | 1 1/2/2014 | 2 是2014年1月3日,则结果将仅包含以下项目:

latestAllowableTimestamp

我可以设法将列表过滤到var output = items.Where(t => (t.Timestamp <= latestAllowableTimestamp)).GroupBy(t => t.Code); 之前的那些时间戳,但我不太了解linq以便为每个代码选择最新的代码并将其插入字典中。< / p>

{{1}}

此时,我最终选择了两个小组,但不知道如何在每个小组中选择一个项目。

3 个答案:

答案 0 :(得分:3)

这是您尝试编写的实际方法。它甚至会返回字典和所有内容:

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

请参阅Enumerable.ToDictionary

答案 1 :(得分:2)

这是你应该在你的问题中发布的部分(正如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();

答案 2 :(得分:0)

要创建词典,可以像这样构建您的查询:

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。