Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Group list entries with LINQ

I have the following model:

public class Entry
{
    public int UseraccountId { get; set; }
    public int CompanyId { get; set; }
    public DateTime CreationDate { get; set; }
    public string Target { get; set; }
    public string Message { get; set; }
}

And a list with a lot of entries:

List<Entry> entries = ... //get all entries.

Example:

Example before grouping

I'd now like row 2 and 3 to be grouped because they have the same UserId, same CompanyId, same target and almost (and this is the difficult part), let's say in a range of 5 seconds, the same date time.

After grouping my list should look like this:

enter image description here

Is there any easy approach for this problem? Any advices? I bet Linq will help me around but I'm not sure how.

Edit: Thank you all for your feedback. I decided to change the design and to ensure that the datetime is now really the same. So grouping with linq is now very easy.

like image 444
mosquito87 Avatar asked Apr 24 '13 15:04

mosquito87


1 Answers

As @dtb menitons, grouping by "close" is difficult because you can end up with a bigger "bucket" than you intended. For example, If you have 100 entries that are created 4 seconds apart from each other, grouping items that are within 5 seconds of the "next" item would put all of them in one bucket!

If, however, you want to round the creating date to the nearest, say, 5 seconds and then group, you could use:

TimeSpan ts = new TimeSpan(0, 0, 5);  // 5 seconds
entries.GroupBy(i => new {
                          UserId = i.UserId, 
                          CompanyId = i.CompanyId, 
                          Target = i.Target, 
                          RoundedTime = DateTime.MinValue.AddTicks(
                                            (long)(Math.Round((decimal)i.CreationDate.Ticks / ts.Ticks) * ts.Ticks)
                                        ) ;
                          ))
       .Select(g => new {
                         UserId = g.Key.UserId, 
                         CompanyId = g.Key.CompanyId, 
                         Target = g.Key.Target, 
                         RoundedTime = g.Key.RoundedTime,
                         Message = string.Join(", ",g.Select(i=> i.Message).ToArray())
                        } );

That will group by items that are rounded to the nearest 5 seconds - it's possible that two items one second apart will be in different buckets, but you don't have the problem with cummutativity that your stated requirement has.

like image 100
D Stanley Avatar answered Oct 19 '22 04:10

D Stanley