2010-10-19 47 views
6

我特別的例子是相當複雜的,但我認爲這個概念同樣適用於類似日誌系統的東西,所以我會用它來代替,以便於解釋。這是一個虛構的例子,請不要喋喋不休或感到苦惱的是achitectually,編程或道德上錯誤的例子本身:)LINQ:從IEnumerable中選擇Distinct/GroupBy並排序 - 可能嗎?

假設你有這樣的:

class LogEntry 
{ 
    int ID; 
    int UserName; 
    datetime TimeStamp; 
    string Details; 
} 

和你拉一組像這樣的數據:

ID Username Timestamp Details 
1 foo  1/01/2010 Account created 
2 zip  2/02/2010 Account created 
3 bar  2/02/2010 Account created 
4 sandwich 3/03/2010 Account created 
5 bar  5/05/2010 Stole food 
6 foo  5/05/2010 Can't find food 
7 sandwich 8/08/2010 Donated food 
8 sandwich 9/09/2010 Ate more food 
9 foo  9/09/2010 Ate food 
10 bar  11/11/2010 Can't find food 

我想要做的就是爲每個用戶選擇(即用戶名的GroupBy)只有最後一個記錄(即排序時間戳降序)。我可以將我的頭腦與Distinct區分開來,但GroupBy的程度較低,但是將所有這些內容組合在一個語句中,該語句也會返回非獨特/分組字段/屬性並按時間戳排序,這讓我很頭疼。

什麼應該站出來與上面的例子是:

ID Username Timestamp Details 
2 zip  2/02/2010 Account created 
8 sandwich 9/09/2010 Ate more food 
9 foo  9/09/2010 Ate food 
10 bar  11/11/2010 Can't find food 

我不想「騙」和訴諸做的長篇大論方式,當性能不是關鍵在這裏,我我們可以在一條LINQ聲明中完全確信它可以完成。

+0

你想如何最終排序? – Will 2010-10-19 05:16:49

回答

14

希望我的LINQ福是正確的這一個:=)

var results = sourceList 
    .OrderByDescending(item => item.Timestamp) 
    .GroupBy(item => item.Username) 
    .Select(grp => grp.First()) 
    .ToArray(); 

使用你的數據此示例代碼,並通過ID最終排序,給出了準確的輸出與您的例子:(如果你不不介意粗糙的格式化!)

class Program 
{ 
    static void Main(string[] args) 
    { 
     var sourceItems = new[] { 
      new LogEntry {ID=1 ,UserName="foo  ", TimeStamp= new DateTime(2010 ,1,01),Details="Account created ",} , 
      new LogEntry {ID=2 ,UserName="zip  ", TimeStamp= new DateTime(2010 ,2,02),Details="Account created ",} , 
      new LogEntry {ID=3 ,UserName="bar  ", TimeStamp= new DateTime(2010 ,2,02),Details="Account created ",} , 
      new LogEntry {ID=4 ,UserName="sandwich ", TimeStamp= new DateTime(2010 ,3,03),Details="Account created ",} , 
      new LogEntry {ID=5 ,UserName="bar  ", TimeStamp= new DateTime(2010 ,5,05),Details="Stole food  ",} , 
      new LogEntry {ID=6 ,UserName="foo  ", TimeStamp= new DateTime(2010 ,5,05),Details="Can't find food ",} , 
      new LogEntry {ID=7 ,UserName="sandwich ", TimeStamp= new DateTime(2010 ,8,08),Details="Donated food ",} , 
      new LogEntry {ID=8 ,UserName="sandwich ", TimeStamp= new DateTime(2010 ,9,09),Details="Ate more food ",} , 
      new LogEntry {ID=9 ,UserName="foo  ", TimeStamp= new DateTime(2010 ,9,09),Details="Ate food  ",} , 
      new LogEntry {ID=10 ,UserName="bar  ", TimeStamp= new DateTime(2010,11,11),Details="Can't find food ",} , 
     }; 

     var results = sourceItems 
      .OrderByDescending(item => item.TimeStamp) 
      .GroupBy(item => item.UserName) 
      .Select(grp => grp.First()) 
      .OrderBy(item=> item.ID) 
      .ToArray(); 

     foreach (var item in results) 
     { 
      Console.WriteLine("{0} {1} {2} {3}", 
       item.ID, item.UserName, item.TimeStamp, item.Details); 
     } 
     Console.ReadKey(); 
    } 
} 


public class LogEntry 
{ 
    public int ID; 
    public string UserName; 
    public DateTime TimeStamp; 
    public string Details; 
} 
+0

看起來不錯。儘管它似乎最終被「ID」排序。 – 2010-10-19 05:14:28

+0

傳說!謝謝。找到不過於簡單的簡單例子有多難。 – nathanchere 2010-10-19 05:15:43

+0

@Jeff:乾杯 - 我已經要求OP澄清這一點。 – Will 2010-10-19 05:17:29