Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I group on one of two possible fields using LINQ?

Tags:

c#

linq

group-by

I am trying to get the latest contact with a given user, grouped by user:

public class ChatMessage
{
    public string SentTo { get; set; }
    public string SentFrom { get; set; }
    public string MessageBody { get; set; }
    public string SendDate { get; set; }
}

The user's contact info could either be in SentTo or SentFrom.

List<ChatMessage> ecml = new List<ChatMessage>();
var q = ecml.OrderByDescending(m => m.SendDate).First();

would give me the latest message, but I need the last message per user. The closest solution I could find was LINQ Max Date with group by, but I cant seem to figure out the correct syntax. I would rather not create multiple List objects if I don't have to. If the user's info is in SentTo, my info will be in SentFrom, and vice-versa, so I do have some way of checking where the user's data is.

Did I mention I was very new to LINQ? Any help would be greatly appreciated.

like image 421
Darkloki Avatar asked Oct 19 '22 14:10

Darkloki


1 Answers

Since you need to interpret each record twice - i.e. as a SentTo and a SentFrom, the query becomes a bit tricky:

var res = ecml
    .SelectMany(m => new[] {
        new { User = m.SentFrom, m.SendDate }
    ,   new { User = m.SentTo, m.SendDate }
    })
    .GroupBy(p => p.User)
    .Select(g => new {
        User = g.Key
    ,   Last = g.OrderByDescending(m => m.SendDate).First()
    });

The key trick is in SelectMany, which makes each ChatMessage item into two anonymous items - one that pairs up the SentFrom user with SendDate, and one that pairs up the SentTo user with the same date.

Once you have both records in an enumerable, the rest is straightforward: you group by the user, and then apply the query from your post to each group.

like image 184
Sergey Kalinichenko Avatar answered Oct 22 '22 02:10

Sergey Kalinichenko