none
Consecutive days - Best way RRS feed

  • Question

  • Hi,

    I have a collection of dates, these dates are not in any order.. I need to find if this collection has any consecutive dates..

    The collection has only days from Mon - Fri.... 

    If a friday and a monday are on the collection ie  6/4/2012 and 9/4/2012.. that is considered to be consecutive

    so is the best way to compare each date with the collection and check to see if the datediff is 1? and have a condition to check for mondays and fridays? (ie date diff 4)

    Thanks

    Vik


    System developer & support analyst

    Thursday, April 5, 2012 3:17 AM

Answers

  • Just trying to clear it up - maybe the message in the other branch got lost - the OP wrote

    "I looped through the collection of dates checking each date to each other.. checking if if the date diff is 1.. (consevutive day) or if the date diff is 3 and checking the weekdays of the two days (in case of friday and monday)"

    I think this is the same approach as RiceD's. However, that's not a problem because, as I also think like Cor, there's not a much more elegant solution than this.


    Armin

    Thursday, April 5, 2012 4:27 PM
  • I'd suggest sorting the dates in order (perhaps in a copy). Then loop through with something like this pseudo-code:

    for d = 0 to NumberOfDates-1
       if date(d) is Friday and date(d+1) is Monday and difference(date(d), date(d+1) = 3 then
          Do True stuff
       else
          if  difference(date(d), date(d+1) = 1 then
              Do True stuff
          else
              Do False stuff
        end if
    end if

    A bit of thought might simplify the ifs but they describe the conditions.


    Regards David R
    ---------------------------------------------------------------
    The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones.
    Object-oriented programming offers a sustainable way to write spaghetti code. - Paul Graham.
    Every program eventually becomes rococo, and then rubble. - Alan Perlis
    The only valid measurement of code quality: WTFs/minute.

    • Proposed as answer by horngsh Thursday, April 5, 2012 10:38 AM
    • Marked as answer by Mike FengModerator Saturday, April 21, 2012 6:43 AM
    Thursday, April 5, 2012 10:29 AM

All replies

  • Vik,

    It sounds like what you're really trying to do is to come up with "is it a weekday?". If so, then you can use this:

    http://msdn.microsoft.com/en-us/library/82yfs2zh(v=VS.80).aspx

    If not then maybe explain a bit more about what you're trying to get.

    Thursday, April 5, 2012 3:31 AM
  • The question here is what are you trying to do with checking these consecutive dates? Return a true or false value? Get a list or a collection/array of these consecutive "dates"? etc...

    If a post helps you in any way or solves your particular issue, please remember to use the Propose As Answer option or Vote As Helpful
    Visit the Forum: TechLifeForum

    Thursday, April 5, 2012 4:07 AM
  • yes just return a true or false date..

    basically here is a list of dates.. tell me if there are any consecutive dates in the list of dates.. true or false..

    I have implemented this.. just wanted to know if there is a better way?

    The way I implemented is..

    I looped through the collection of dates checking each date to each other.. checking if if the date diff is 1.. (consevutive day) or if the date diff is 3 and checking the weekdays of the two days (in case of friday and monday)


    System developer & support analyst

    Thursday, April 5, 2012 4:54 AM
  • yes just return a true or false date..

    basically here is a list of dates.. tell me if there are any consecutive dates in the list of dates.. true or false..

    I have implemented this.. just wanted to know if there is a better way?

    The way I implemented is..

    I looped through the collection of dates checking each date to each other.. checking if if the date diff is 1.. (consevutive day) or if the date diff is 3 and checking the weekdays of the two days (in case of friday and monday)


    System developer & support analyst

    Vik,

    AFAIK there is no other way and then probably also not a "better" way. Be aware that short written code using expressions does not always end with a faster program. (Of course real steps can make a difference but I would not know how that would be done in your case. There is no function which returns simply what you want to get). I don't know if you used DateDiff or TimeSpan and that is also only optical and does not change much in the performance.


    Success
    Cor



    • Edited by Cor Ligthert Thursday, April 5, 2012 7:51 AM wordiness
    Thursday, April 5, 2012 5:26 AM
  • I'd suggest sorting the dates in order (perhaps in a copy). Then loop through with something like this pseudo-code:

    for d = 0 to NumberOfDates-1
       if date(d) is Friday and date(d+1) is Monday and difference(date(d), date(d+1) = 3 then
          Do True stuff
       else
          if  difference(date(d), date(d+1) = 1 then
              Do True stuff
          else
              Do False stuff
        end if
    end if

    A bit of thought might simplify the ifs but they describe the conditions.


    Regards David R
    ---------------------------------------------------------------
    The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones.
    Object-oriented programming offers a sustainable way to write spaghetti code. - Paul Graham.
    Every program eventually becomes rococo, and then rubble. - Alan Perlis
    The only valid measurement of code quality: WTFs/minute.

    • Proposed as answer by horngsh Thursday, April 5, 2012 10:38 AM
    • Marked as answer by Mike FengModerator Saturday, April 21, 2012 6:43 AM
    Thursday, April 5, 2012 10:29 AM
  • Riced,

    That is in my perception the solution the OP has done, he ask for better ways.

    :-)


    Success
    Cor

    Thursday, April 5, 2012 11:04 AM
  • Cor

    Not so - OP says they are not in any order. And that makes a difference as to how you can do the comparisons.

    By sorting you get it down to order N, otherwise it's N^2. I think that's about right - sorting means you can use one loop; unsorted means using loop within loop. Of course I might have misunderstood the OP's situation.


    Regards David R
    ---------------------------------------------------------------
    The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones.
    Object-oriented programming offers a sustainable way to write spaghetti code. - Paul Graham.
    Every program eventually becomes rococo, and then rubble. - Alan Perlis
    The only valid measurement of code quality: WTFs/minute.

    Thursday, April 5, 2012 11:20 AM
  • Cor

    Not so - OP says they are not in any order. And that makes a difference as to how you can do the comparisons.


    David, 

    He does not say that, he says they do not start in any order, and then he gives a solution which is the same likewise yours.

    Be aware, I was starting like you before I became aware of the real question of the OP. Therefore I recognized you did the same.



    Success
    Cor


    Thursday, April 5, 2012 2:43 PM
  • Cor

    Not so - OP says they are not in any order. And that makes a difference as to how you can do the comparisons.


    David, 

    He does not say that, he says they do not start in any order, and then he gives a solution which is the same likewise yours.

    Be aware, I was starting like you before I became aware of the real question of the OP. Therefore I recognized you did the same.



    Success
    Cor


    Based on precisely what the OP stated - the dates are not in any order. 'Starting' is irrelevant. The OPs solution also indicates that the dates are not likely to be sorted.

    Additionally, Riced's solution is different from the OPs solution: the OP appears to have (as already mentioned) a Loop-within-a-loop, while Riced (David R.) offers a valid alternative, a Sort-then-a-loop. Davids solution is NOT the same as the OPs solution.

    As far which is 'best' depends on what 'best' means. Both are valid. Even considering that a sort is a 'loop within a loop' itself, the sort-then-loop would be marginally faster depending on the sort algorithm. If a sorted collection could be used (potentially) elsewhere for other calculations, then sorting first would be a no-brainer. Either way, it cannot be done without loops, and I cannot think of a more straightforward way other than the OPs solution or Davids solution (which has been marked as a potential answer).


    Stephen J Whiteley

    Thursday, April 5, 2012 4:17 PM
    Moderator
  • Just trying to clear it up - maybe the message in the other branch got lost - the OP wrote

    "I looped through the collection of dates checking each date to each other.. checking if if the date diff is 1.. (consevutive day) or if the date diff is 3 and checking the weekdays of the two days (in case of friday and monday)"

    I think this is the same approach as RiceD's. However, that's not a problem because, as I also think like Cor, there's not a much more elegant solution than this.


    Armin

    Thursday, April 5, 2012 4:27 PM
  • Maybe I'm making much ado of nothing (it wouldn't be the first time), but it seems to me that a DateDiff value of 4 is Monday and Friday of the same week because the DayOfWeek enumerator is reset to 0 on the first day of the week.

    The following may be totally not needed, but for what it's worth:

    Public Class ConsecutiveDate Public Date1 As DateTime Public Date2 As DateTime End Class ' Private rand As New Random ' Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load Dim dList As New List(Of DateTime) Dim resultList As New List(Of ConsecutiveDate) ' For i As Integer = 1 To 2000 Dim offset As Integer = rand.Next(1, 2000) Dim d As DateTime = Today.AddDays(offset) If Not dList.Contains(d) Then dList.Add(d) End If Next ' Dim allDaysTextFile As String = _ My.Computer.FileSystem.SpecialDirectories.Desktop & "\AllDays.txt" Dim sb As New System.Text.StringBuilder ' For i As Integer = 0 To dList.Count - 1 sb.AppendLine(dList(i).ToLongDateString) Next ' My.Computer.FileSystem.WriteAllText(allDaysTextFile, sb.ToString, False) ' dList.Sort() ' For i As Integer = 0 To dList.Count - 1 If i > 0 Then Dim dayBefore As DateTime = dList(i - 1) Dim thisDay As DateTime = dList(i) Dim containsFriday As Boolean = False If dayBefore.DayOfWeek = DayOfWeek.Friday OrElse _ thisDay.DayOfWeek = DayOfWeek.Friday Then containsFriday = True End If ' If dayBefore.DayOfWeek > DayOfWeek.Sunday AndAlso _ dayBefore.DayOfWeek < DayOfWeek.Saturday Then ' If thisDay.DayOfWeek > DayOfWeek.Sunday AndAlso _ thisDay.DayOfWeek < DayOfWeek.Saturday Then ' If containsFriday Then ' Determine which of them is Friday If dayBefore.DayOfWeek = DayOfWeek.Friday Then If thisDay.DayOfWeek = DayOfWeek.Monday Then Dim thisDateSet As New ConsecutiveDate With thisDateSet .Date1 = dayBefore .Date2 = thisDay End With resultList.Add(thisDateSet) End If Else If dayBefore.DayOfWeek = DayOfWeek.Monday Then If DateDiff(DateInterval.Day, dayBefore, thisDay) = 4 Then Dim thisDateSet As New ConsecutiveDate With thisDateSet .Date1 = dayBefore .Date2 = thisDay End With resultList.Add(thisDateSet) End If End If End If Else If DateDiff(DateInterval.Day, dayBefore, thisDay) = 1 Then Dim thisDateSet As New ConsecutiveDate With thisDateSet .Date1 = dayBefore .Date2 = thisDay End With resultList.Add(thisDateSet) End If End If End If End If End If Next ' Dim consecutiveDaysFile As String = _ My.Computer.FileSystem.SpecialDirectories.Desktop & "\ConsecutiveDays.txt" sb.Length = 0 ' For i As Integer = 0 To resultList.Count - 1 If i > 0 Then sb.AppendLine() sb.AppendLine("------------------------------") sb.AppendLine() End If sb.AppendLine(resultList(i).Date1.ToLongDateString) sb.AppendLine(resultList(i).Date2.ToLongDateString) Next ' My.Computer.FileSystem.WriteAllText(consecutiveDaysFile, sb.ToString, False) Stop End Sub

    This is the random list of dates that it generated:

    Click To Open

    and this is the "sets" of consecutive days that it generated:

    Click To Open

    ...for what it's worth

    Thursday, April 5, 2012 4:48 PM
  • I screwed that up - I just went and added the datediff=4 anyway and my intent was to generate ANOTHER list to show what I meant of those which are Monday and Friday of the same week.

    Hopefully it makes sense but as it is, you'll need to remove that entire "else" segment".

    Thursday, April 5, 2012 4:53 PM
  • Yes - here's the list of those it found that have a datediff=4:

    http://www.fls-tech.com/VBNet_Forum/04-05-12/DateDiff_4.txt

    Thursday, April 5, 2012 5:06 PM
  • Maybe I'm overlooking something, but this should do it:

       Shared Function HasConsecutiveDays(ByVal Values As IEnumerable(Of DateTime)) As Boolean
    
          Dim Indexes = (From d In Values Order By d _
                  Select DayIndex = (d.Date - DateTime.MinValue).Days _
                  Select Dayindex = (DayIndex \ 7) * 5 + (DayIndex Mod 7)).ToArray
    
          Return Aggregate i In Indexes.Skip(1).Where(Function(i, LoopIndex) Indexes(LoopIndex) = i - 1) Into Any()
    
       End Function

    EDIT: The function is map is each day to a day number, then scales it to 5 days a week. The final value is comparable without a week end gap.


    Armin


    Thursday, April 5, 2012 5:21 PM
  • Maybe I'm overlooking something, but this should do it:

       Shared Function HasConsecutiveDays(ByVal Values As IEnumerable(Of DateTime)) As Boolean
    
          Dim Indexes = (From d In Values Order By d _
                  Select DayIndex = (d.Date - DateTime.MinValue).Days _
                  Select Dayindex = (DayIndex \ 7) * 5 + (DayIndex Mod 7)).ToArray
    
          Return Aggregate i In Indexes.Skip(1).Where(Function(i, LoopIndex) Indexes(LoopIndex) = i - 1) Into Any()
    
       End Function


    Armin

    Wow - you're much better in LINQ than I am (well heck, you're much better with all of it than me), so if you say that it works I'll take your word on it!

    Do you see my point though about a DateDiff=4 as being the Monday and Friday of the same week?

    Thursday, April 5, 2012 5:27 PM
  • Cor

    Compare these the first is the OP's solution as I see it, the second is what I suggested might be a way to do it. I'd say they are not the same.

    The Op's method as inferred from description
       ' declare variables i, j, found
       ' init i = 0, found = false
       while not found AndAlso i < numberOfDates
          j = 0
          while not found AndAlso j < numberOfDates
             found = DaysAreConsecutive(dates(i), dates(j))
          end while
       end while
    (Depending on how DaysAreConsecutive is implemented the inner loop could go from j=i+1.)

    Another method - may be better depends on what is meant and the data
       ' declare variables i, found
       ' init i = 0, found = false
       SortDates()
       while not found AndAlso i < numberOfDates-1
          found = DaysAreConsecutive(dates(i), dates(i+1))
       end while
    Based on the actual wording in the original post there is no basis to assume any ordering has been done by the OP.

    I can't claim my method is better. It might be, but depends on such things as volume of data. If there are only a few it will make little difference. On the other hand it could make quite a difference. I once changed an implementation from the (inferred) OP's method to my method, run time reduced from over 50mins to under 2mins.


    Regards David R
    ---------------------------------------------------------------
    The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones.
    Object-oriented programming offers a sustainable way to write spaghetti code. - Paul Graham.
    Every program eventually becomes rococo, and then rubble. - Alan Perlis
    The only valid measurement of code quality: WTFs/minute.

    Thursday, April 5, 2012 6:11 PM
  • I'm not completely sure if it works. :) Someone'd better ran some tests. LINQ's hard to debug.

    I don't use the DateDiff function, but, yes, it's 4 days.


    Armin

    Thursday, April 5, 2012 6:26 PM
  • I don't use the DateDiff function, but, yes, it's 4 days.


    Armin

    It's a nice function because it takes in such things as leap year and it's pretty fast.

    But given these three conditions:

    - The two days are weekdays (ergo, not Saturday nor Sunday)
    - One of the days is Friday
    - The days between is four

    It HAS to be Monday and Friday of the same week. If it's looking at Monday of the following week the difference will be negative because on Sunday, the enumerator is reset back to zero.

    Thursday, April 5, 2012 6:29 PM
  • Frank, Armin

    I think the OP made a typo in first post (i.e. 4) because in second post used 3 (which is correct for Friday to Monday).

    I think it's not only hard to debug (I'll take your word for that) but borders on incomprehensibility. But that's just an old man's take on LINQ in general. :)


    Regards David R
    ---------------------------------------------------------------
    The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones.
    Object-oriented programming offers a sustainable way to write spaghetti code. - Paul Graham.
    Every program eventually becomes rococo, and then rubble. - Alan Perlis
    The only valid measurement of code quality: WTFs/minute.

    Thursday, April 5, 2012 6:33 PM
  • Frank, Armin

    I think the OP made a typo in first post (i.e. 4) because in second post used 3 (which is correct for Friday to Monday).

    I think it's not only hard to debug (I'll take your word for that) but borders on incomprehensibility. But that's just an old man's take on LINQ in general. :)


    Regards David R
    ---------------------------------------------------------------
    The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones.
    Object-oriented programming offers a sustainable way to write spaghetti code. - Paul Graham.
    Every program eventually becomes rococo, and then rubble. - Alan Perlis
    The only valid measurement of code quality: WTFs/minute.

    Ah ok - and depending on which direction you use for Date1 and Date2, yes that's possible.

    As for LINQ, it's really quite powerful but you're right, debugging it when it doesn't work is a pain. About the only way that I ever have been able to is to "build it up" little at a time and keep testing it over and over.

    But if it later just doesn't work for some weird reason or another ... you're back to tearing it apart again and testing.

    In something that I wrote the other day (for a forum member) I tried something I'd been thinking of for a while. Let's say that you have a database of names. Four names which really ARE the same thing ... but hard to evaluate might be:

    - "Frank Smith"
    - "frank smith"
    - "FrankSmith"
    - "Frank      Smith"

    I used LINQ to resolve it and it's not that tough at all. This is totally off-topic for this thread but let me know if you'd like me to post the solution. It's actually just a few lines of code using LINQ.

    Thursday, April 5, 2012 6:40 PM
  • But given these three conditions:

    - The two days are weekdays (ergo, not Saturday nor Sunday)
    - One of the days is Friday
    - The days between is four

    It HAS to be Monday and Friday of the same week. If it's looking at Monday of the following week the difference will be negative because on Sunday, the enumerator is reset back to zero.

    I'm not quite sure what's the point. That's only of you don't consider the week. If you're referring to my code (are you?), I'm multiplying the week by 5 before adding the day offset (0..4), so the next monday is always greater than the friday before.

    Armin

    Thursday, April 5, 2012 6:45 PM
  • I'm not quite sure what's the point. That's only of you don't consider the week. If you're referring to my code (are you?), I'm multiplying the week by 5 before adding the day offset (0..4), so the next monday is always greater than the friday before.

    Armin

    No, I was referring to the OP's logic (although David said that he later said three days), but originally he said "... and have a condition to check for mondays and fridays? (ie date diff 4)..."

    If one day is a Friday and the DateDiff=4 then the other date has to be Monday of that same week (unless he's taking absolute value - or interchanging D1 for D2 - in which case it could also be Tuesday of the following week).



    But either way, they aren't "consecutive days" in the sense that's he's asking about...

    Thursday, April 5, 2012 6:50 PM
  • No, I was referring to the OP's logic (although David said that he later said three days), but originally he said "... and have a condition to check for mondays and fridays? (ie date diff 4)..."

    If one day is a Friday and the DateDiff=4 then the other date has to be Monday of that same week (unless he's taking absolute value - or interchanging D1 for D2 - in which case it could also be Tuesday of the following week).

    Well, yes, no, ummm, yes,  LOL     It's 4 days in one direction and 3 in the other one. I think he means to exclude (not include) a difference of 4 days to be recognized it as two consecutive days. Depends on the point of view.


    Armin

    Thursday, April 5, 2012 7:10 PM
  • No, I was referring to the OP's logic (although David said that he later said three days), but originally he said "... and have a condition to check for mondays and fridays? (ie date diff 4)..."

    If one day is a Friday and the DateDiff=4 then the other date has to be Monday of that same week (unless he's taking absolute value - or interchanging D1 for D2 - in which case it could also be Tuesday of the following week).

    Well, yes, no, ummm, yes,  LOL     It's 4 days in one direction and 3 in the other one. I think he means to exclude (not include) a difference of 4 days to be recognized it as two consecutive days. Depends on the point of view.


    Armin

    I agree - what he's asked for leaves a lot to be desired.

    For instance, is he passing in a list (he never said what sort of collection it was) of all dates or just evaluating each two dates at a time? Does he want a boolean indicating that they're "consecutive" in the sense that he means or does he want a list of all consecutive ones back, given a starting date and ending date or ...?

    It's wide open right now.

    I look forward to seeing if he'll expound on what he's passing in and what he wants back.

    Thursday, April 5, 2012 7:15 PM
  • I would say quite simply, as the OP has quite simply stated, a Friday followed by (the following) Monday is a consecutive day. Regardless of how you determine it, this should return true for the function.

    Public Class Form1
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            ' Should be consecutive (spans a weekend)
            Dim d() As DateTime = New DateTime() {#4/4/2012#, #4/6/2012#, #4/9/2012#, #4/11/2012#, #4/13/2012#, #4/17/2012#, #4/19/2012#}
            Dim result As Boolean = Consecutive(d)
            Debug.WriteLine(result)
            ' Should be consecutive (two weekdays)
            d = New DateTime() {#4/4/2012#, #4/6/2012#, #4/10/2012#, #4/11/2012#, #4/13/2012#, #4/17/2012#, #4/19/2012#}
            result = Consecutive(d)
            Debug.WriteLine(result)
            ' Should NOT be consecutive
            d = New DateTime() {#4/4/2012#, #4/6/2012#, #4/10/2012#, #4/12/2012#, #4/14/2012#, #4/16/2012#, #4/18/2012#}
            result = Consecutive(d)
            Debug.WriteLine(result)
        End Sub
    
        Public Function Consecutive(dates() As DateTime) As Boolean
            Call Array.Sort(dates)
            Dim prev As DateTime
            For Each d As DateTime In dates
                ' Ignore saturday and sundays
                If d.DayOfWeek = DayOfWeek.Saturday OrElse d.DayOfWeek = DayOfWeek.Sunday Then Continue For
                ' get just the date
                Dim dt As DateTime = d.Date
                Dim dayDifference As Integer = dt.Subtract(prev).Days
                If dayDifference = 1 Then Return True
                If dt.DayOfWeek = DayOfWeek.Monday AndAlso dayDifference = 3 Then Return True
                ' Set the previous date
                prev = dt
            Next
            Return False
        End Function
    End Class
    I'm not a fan of LINQ (it's kind of an electric hammer 'as seen on TV') so the above is an alternative, pretty much replicating what David R was demonstrating with the pseudo-code.

    Stephen J Whiteley


    Thursday, April 5, 2012 8:10 PM
    Moderator