2010-05-29 68 views
2

我无法将这一点逻辑转换成Linq语句,这让我发疯。我有一个项目列表有一个类别和一个createdondate字段。我想按类别进行分组,并只返回具有其类别最大日期的项目。如何将此逻辑转换为LINQ语句?

因此,例如,列表包含具有类别1和2的项目。第一天(1/1)我将两个项目发布到类别1和2中。第二天(1/2)我将三个项目发布到类别1.该列表应将第二天的发布返回到类别1,并将第一天的发布返回到类别2.

现在,我已将它按类别分组,然后运行foreach循环,以便将组中的每个项目与该组的最大日期,如果日期小于它删除该项目的最大日期。

有一种方法可以把环路拿出来,但我还没弄明白!

回答

2

你可以做这样的事情:

from item in list 
    group item by item.Category into g 
    select g.OrderByDescending(it => it.CreationDate).First(); 

然而,这不是很有效,因为它需要每一个组,这比需要的更复杂的项目进行排序(你实际上并不需要排序,你只需要扫描一次)。所以我创造了这个扩展方法与属性的最大值(或功能)寻找项目:

from item in list 
    group item by item.Category into g 
    select g.WithMax(it => it.CreationDate); 

UPDATE:

public static T WithMax<T, TValue>(this IEnumerable<T> source, Func<T, TValue> selector) 
    { 
     var max = default(TValue); 
     var withMax = default(T); 
     var comparer = Comparer<TValue>.Default; 
     bool first = true; 
     foreach (var item in source) 
     { 
      var value = selector(item); 
      int compare = comparer.Compare(value, max); 

      if (compare > 0 || first) 
      { 
       max = value; 
       withMax = item; 
      } 
      first = false; 
     } 
     return withMax; 
    } 

您可以按如下方式使用它作为安东尼在他的评论中指出,这段代码并不完全回答这个问题......如果你想要所有日期是其类别的最大值的项目,你可以这样做:

from item in list 
    group item by item.Category into g 
    let maxDate = g.Max(it => it.CreationDate) 
    select new 
    { 
     Category = g.Key, 
     Items = g.Where(it => it.CreationDate == maxDate) 
    }; 
+0

此代码似乎只拉取类别中具有等于该类别的最大日期的类别中的第一项。问题是要求类别中的所有项目都是该类别的最大计数日期。 – 2010-05-29 21:49:19

+0

好点...我更新了我的答案 – 2010-05-29 22:03:50

+0

事实证明,你的代码已经关闭了,但我的阅读需求也是如此。尽管在我自己的批评中出现了错误,但第二次做得很好。 – 2010-05-29 22:14:36

1

如何:

private class Test 
    { 
     public string Category { get; set; } 
     public DateTime PostDate { get; set; } 
     public string Post { get; set; } 
    } 
    private void Form1_Load(object sender, EventArgs e) 
    { 
     List<Test> test = new List<Test>(); 
     test.Add(new Test() { Category = "A", PostDate = new DateTime(2010, 5, 5, 12, 0, 0), Post = "A1" }); 
     test.Add(new Test() { Category = "B", PostDate = new DateTime(2010, 5, 5, 13, 0, 0), Post = "B1" }); 

     test.Add(new Test() { Category = "A", PostDate = new DateTime(2010, 5, 6, 12, 0, 0), Post = "A2" }); 
     test.Add(new Test() { Category = "A", PostDate = new DateTime(2010, 5, 6, 13, 0, 0), Post = "A3" }); 
     test.Add(new Test() { Category = "A", PostDate = new DateTime(2010, 5, 6, 14, 0, 0), Post = "A4" }); 

     var q = test.GroupBy(t => t.Category).Select(g => new { grp = g, max = g.Max(t2 => t2.PostDate).Date }).SelectMany(x => x.grp.Where(t => t.PostDate >= x.max)); 
    } 
+0

这将计算类别中每个项目的类别的最大值......效率不高。您应该在Where过滤器之前计算最大值 – 2010-05-29 22:20:06

+0

@Thomas - 更改,谢谢。 – Luc 2010-05-29 23:23:23

0

重新格式化LUC的出色答卷查询理解的形式。我更喜欢这种查询方式,因为范围规则让我可以更简洁地编写。

from item in source 
    group item by item.Category into g 
    let max = g.Max(item2 => item2.PostDate).Date 
    from item3 in g 
    where item3.PostDate.Date == max 
    select item3;