Select from IEnumerable with Distinct / GroupBy and do the sorting - maybe?

Let's say you have this:

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

and you pulled out a dataset like this:

 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 

What I want to do is select only the last individual record (i.e. Sort on TimeStamp Descending) for each user (i.e. GroupBy username). I can deal with Distinct and GroupBy, but combining them into a single expression that also returns undifferentiated / grouped fields / properties AND sorting by timestamp causes me a headache.

What should happen with the above example:

 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 

I donโ€™t want to โ€œdeceiveโ€ and resort to a multifaceted way to do this when I am sure that this can be done with a single LINQ statement.

+9
c # linq distinct
source share
1 answer

I hope my Linq-fu is right on this one: =)

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

This example code using your data and the final order by ID gives exactly the same result as your example: (if you do not mind rough formatting!)

 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; } 
+18
source share

All Articles