开发者

Select from IEnumerable with Distinct/GroupBy and sorting — possible?

Say you have this:

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

and you have pulled a set of 开发者_C百科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;
}


The accepted answer is correct and works, but there's now an easier way to do this since DistinctBy has been added to LINQ.

var results = source
    .OrderByDescending(item => item.Timestamp) // Order however you want
    .DistinctBy(item => item.Username);        // Distincts by the key provided

DistinctBy does exactly the same as if you would GroupBy first and then Select the first item in each group. It might even be more performant.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜