2012-02-29 55 views
5

我有如下3个属性的MyItem类从对象列表中选择:LINQ:分组依据,并根据最大值

class MyItem 
{ 
    private string _name; 
    private int _value 
    private DateTime _TimeStamp; 

    public MyItem(string name, int value, string timeStamp) 
    { 
     this._name = name; 
     this._value = value; 
     this._timeStamp = DateTime.Parse(timeStamp); 
    } 

    public string Name 
    { get {return this_name; } } 

    public int Value 
    { get {return this._value; } } 

    public DateTime TimeStamp 
    { get {return this._timeStamp; } } 

    // ... 
} 

我也有如下MyItem列表:

var myItems = new List<MyItem>() { 
    new MyItem("A", 123, "23/02/2012"), 
    new MyItem("A", 323, "22/02/2012"), 
    new MyItem("B", 432, "23/02/2012"), 
    new MyItem("B", 356, "22/02/2012"), 
    // ... 
} 

我怎么能GROUP BY myList,以便我只剩下具有最大时间戳的项目?即结果如下:

"A" 123 23/02/2012<br> 

"B" 432 23/02/2012<br> 

在此先感谢。

+0

我冒昧地编辑你的代码,我希望我没有搞砸你的例子 – BlackBear 2012-02-29 20:38:33

回答

6
myItems.GroupBy(item => item.Name) 
     .Select(grp => grp.Aggregate((max, cur) => 
          (max == null || cur.Date > max.Date) ? cur : max)) 

这将选择在最快的时间内你的结果(至少我可以计算),而无需创建新的对象和遍历收集次数最少。

+0

正是我需要的。在我从数据库中提取的具有匹配日期和不同值的记录中,我希望获得最高的价值。你摇滚人感谢。 – 2015-12-22 18:56:44

0
var tmp = select i from myItems 
group i by i.Name into g 
select new MyItem 
{ 
    g.Name, 
    Value = g.OrderByDescending(x => x.Timestamp).First().Value, 
    Timestamp = g.Max(x => x.Timestamp) 
}; 
+0

这不会编译队友。 – MaYaN 2012-02-29 20:41:46

+0

我忘记了“进入g”。如果你想使用,你需要学习linq。 – 2012-02-29 20:45:53

3

本集团选择最高:

from item in MyItems 
group item by item.Name into grouped 
let maxTimeStamp = grouped.Max(i => i.TimeStamp) 
select grouped.First(i => i.TimeStamp == maxTimeStamp) 
+0

@ ALIR.Bousari - 你是对的。查询的select语句创建* new *'MyItem'并使用[object initializer](http://msdn.microsoft.com/en-us/library/bb397680.aspx)来设置属性。 – 2012-02-29 21:26:34

+0

@ChristopherCurrens - tnx的澄清,但你可以从我最近的编辑上面看到,我的属性只有getter,所以不能在这里设置它们,我真的不想创建新的对象。 – MaYaN 2012-02-29 21:34:42

+0

@ ALIR.Bousari - 我明白了。那么,我会恢复我的答案。它比这些更复杂,这就是为什么我删除它,但它不会创建新的对象。 – 2012-02-29 21:41:26

1
var temp = myItems.Where(x => x.TimeStamp == myItems.Where(y => y.Name == x.Name).Max(z => z.TimeStamp)).Distinct().ToList(); 
+0

太棒了!正是我想要的。非常感谢你:-) – MaYaN 2012-02-29 20:59:59

+1

@ ALIR.Bousari - 虽然这个答案产生你期望的输出,但它是一个非常慢的算法:O(n^2)。我将执行速度与@ JoeTuskan的答案进行了比较,在执行查询的列表中只有* 1000个项目执行了5次查询。这个答案使用了'00:00:15.8860736',而乔只使用了'00:00:00.0080155'。 – 2012-02-29 21:16:28

+0

@ Christopher,谢谢你的分析,这肯定会影响到列表变大(这是我的情况),我无法实现Joe的解决方案,因为我无法理解SELECT部分​​ – MaYaN 2012-02-29 21:22:26

0

OK,我改变了你MyItem类一些LINQ方便(希望这不会导致问题),通过添加一个空的构造函数的类:

public MyItem() { }

在一个示例控制台程序,此代码将工作:

static void Main(string[] args) 
{ 
    var myItems = new List<MyItem>() 
    { 
     new MyItem("A", 123, "23/02/2012"), 
     new MyItem("A", 323, "22/02/2012"), 
     new MyItem("B", 432, "23/02/2012"), 
     new MyItem("B", 356, "22/02/2012") 
     // ... 
    }; 

    var grouped = from m in myItems 
        group m by m.Name into g 
        let maxTimestamp = g.Max(t => t.TimeStamp) 
        select new MyItem 
        { 
         Name = g.Key, 
         Value = g.First(f => f.TimeStamp == maxTimestamp).Value, 
         TimeStamp = maxTimestamp 
        }; 
    foreach (var gItem in grouped) 
    { 
     Console.WriteLine(gItem.Name + ", " + gItem.Value + ", " + gItem.TimeStamp); 
    } 

    Console.ReadLine(); 
} 

输出符合您的预期结果。