views:

68

answers:

1

I have a table that records when a user views a page. The table looks something like this:

ID | Date
1  | 01/01/10 00:00:01.000
2  | 03/01/10 00:00:01.000
3  | 03/01/10 00:00:02.000
4  | 04/01/10 00:00:01.000
5  | 05/01/10 00:00:01.000
6  | 05/01/10 00:00:02.000
7  | 05/01/10 00:00:03.000

Using Linq-to-SQL I want to count the last group of consecutive days a page was viewed, but of course I'm not sure how I would go about doing this. For example, running the query on the data above should return 3.

Any help would be muchly appreciated :)

+1  A: 

This is the test data. I added 6th Oct at the end of list to make sure the result only pick up last consecutive date set.

List<DateTime> viewDates = new List<DateTime>();
viewDates.Add(new DateTime(10, 10, 1));
viewDates.Add(new DateTime(10, 10, 3));
viewDates.Add(new DateTime(10, 10, 3));
viewDates.Add(new DateTime(10, 10, 4));
viewDates.Add(new DateTime(10, 10, 5));
viewDates.Add(new DateTime(10, 10, 5));
viewDates.Add(new DateTime(10, 10, 5));
viewDates.Add(new DateTime(10, 10, 6));



First, we need to find out the last consecutive date:

var lastConsecutiveDate = viewDates
                .Distinct()
                .Reverse()
                .SkipWhile(distinctDate => viewDates.Where(viewDate => (viewDate.Date == distinctDate.Date)).Count() < 2).FirstOrDefault();



We have 2 choices here, to use foreach or LINQ? foreach is more readable compared to LINQ. I will show both implementations.

This is the implementation for foreach:

var consecutiveDates = new List<DateTime>();
foreach (var item in viewDates.Where(viewDate => viewDate <= lastConsecutiveDate).Distinct().OrderByDescending(a => a.Date))
{

    //break if datediff is not 1
    int count = consecutiveDates.Count;
    if ((count > 0) && (consecutiveDates[count - 1].Date.AddDays(-1) != item.Date))
    {
        break;
    }

    consecutiveDates.Add(item);
}



This is the implementation for LINQ, less readable:

var consecutiveDates = viewDates
    .Where(viewDate => viewDate <= lastConsecutiveDate)
    .Distinct()
    .OrderByDescending(viewDate => viewDate.Date)
    .Aggregate
    (
        new { List = new List<DateTime>() },
        (result, viewDate) =>
        {
            int count = result.List.Count;
            if ((count > 0) && (result.List[count - 1].Date.AddDays(-1) != viewDate.Date))
            {
                return new { result.List };
            }

            result.List.Add(viewDate);
            return new { result.List };
        },
        a => a.List
    );

Console.WriteLine(consecutiveDates.Count()); will print out "3". I am expecting more refactoring on my code, but I am off for break.

Lee Sy En
This query has nothing to do with consecutive days, it just returns the number of views for a day.
Dan Dumitru
ouch.. I misunderstood asker's question. I have edited my code. (-2 is painful..)
Lee Sy En
I understand your pain, and I'll happily change my vote, but you misunderstood the question again. As the OP says in the comment, he's after *the number of consecutive days*, and not the number of views in a lastConsecutiveDay. It should be something like distinct, revert, and then count how many of the days are consecutive... I don't know how to do it with Linq, but your solution is still off.
Dan Dumitru
Re-edit for second time =/
Lee Sy En