Say you have this:
class LogEntry
{
int ID;
int UserName;
datetime TimeStamp;
string Details;
}
and you have pulled a set of data 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 single record (ie Sort on TimeStamp Descending) for each user (ie GroupBy Username). I can get my head around Distinct and GroupBy, but combining them in a single statement which also returns the non-distinct/grouped fields/properties AND sorts by timestamp is giving me a headache.
What should come out with the above example is:
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 'cheat' and resort to a long-winded way of doing it when I'm confident it can be done in a single LINQ statement.
Hopefully 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 sample code using your data, and final ordering by ID, gives exactly the same output as your example: (if you don't mind the crude 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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With