Challenge: Un-Recursive (Simple?)

  • (4 Pages)
  • +
  • 1
  • 2
  • 3
  • 4

50 Replies - 20027 Views - Last Post: 18 September 2013 - 04:57 AM

#16 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2271
  • View blog
  • Posts: 9,500
  • Joined: 29-May 08

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 09:52 AM

andrewsw: Wrong.
Was This Post Helpful? 0
  • +
  • -

#17 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2271
  • View blog
  • Posts: 9,500
  • Joined: 29-May 08

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 01:03 PM

View Postandrewsw, on 04 May 2013 - 05:48 PM, said:

Spoiler


Correction it does work. Sorry. :surrender:/>

I thought day of week didn't start on a Sun
UnixTime Epoch begin on a Thursday.
Also don't like that it use the DayOfWeek Enum as if was a value.
I think it is a little brittle, if the values are changed.

To me it has a lot of repetition and recalculation. Like the dte.DayOfWeek Mod 6 = 0.
Yes, it on a different instance of dte

  Public Function AddWorkDays(ByVal dte As Date, ByVal x As Integer) As Date
        Dim a = If(x < 0, -1, 1)
        While x <> 0 Or (dte.DayOfWeek Mod 6 = 0)
            dte = dte.AddDays(a)
            x -= If(x = 0 Or (dte.DayOfWeek Mod 6 = 0), 0, a)
        End While
        Return dte
    End Function






The following of mine is little heavy with the anonymous iterator lambda.
Public  Function AddWorkDays(d As Date, wd As integer) As Date
    Return (Iterator  Function()
              Dim a = If(wd<0,-1,1)
              While True
                If d.DayOfWeek.IsAnyOfThese({DayOfWeek.Saturday, DayOfWeek.Sunday}) Then
                   d = d.AddDays(a)
                Else
                  Yield d  
                  If wd<>0 Then         
                     d = d.AddDays(a)
                     wd -= a
                  Else 
                    Exit While 
                  End If
              End If 
             End While
           End Function)().Last 
  End Function


Also don't like that it uses While True there a chance of infinite looping.
Don't know if a theorem proofer would mark it a safe to use cos if converges
And the calculation of the next date is done twice.

So this is my current implementation.
  Public Function AddWorkDays_B( InitialDate As Date,
                                 WorkingDays As Integer
                               ) As Date
    REM --- Variable used ---
    Dim FromDateCalculated   = InitialDate 
    Dim Delta                = If(WorkingDays < 0, -1, 1)
    Dim CalculationsAreDone  = False
    REM --- Lambda Functions ---
    Dim IsNonWorkDay         = Function(ds As Date) ds.DayOfWeek.IsAnyOfThese({DayOfWeek.Saturday, DayOfWeek.Sunday})
    Dim DateForNextIteration = Function(ds As Date) ds.AddDays(Delta)
    REM -- Start of Calculation Iteration ---
    Do
      If IsNonWorkDay ( FromDateCalculated ) then
         FromDateCalculated = DateForNextIteration(FromDateCalculated)
      ElseIf WorkingDays <> 0 Then
         FromDateCalculated = DateForNextIteration(FromDateCalculated)
         REM --- Decrement Working Days by the Delta
         WorkingDays -= Delta
       Else
          CalculationsAreDone = True  
      End If 
    Loop Until CalculationsAreDone  
    Return FromDateCalculated
  End Function



The thing the slightly bugs be is this
   If IsNonWorkDay ( FromDateCalculated ) then
         FromDateCalculated = DateForNextIteration(FromDateCalculated)
      ElseIf WorkingDays <> 0 Then
         FromDateCalculated = DateForNextIteration(FromDateCalculated)
         REM --- Decrement Working Days by the Delta
         WorkingDays -= Delta



The two branches are almost identical expect for WorkingDays -= Delta .

Don't repeat yourself senses tingling.

This post has been edited by AdamSpeight2008: 04 May 2013 - 01:30 PM

Was This Post Helpful? 0
  • +
  • -

#18 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2271
  • View blog
  • Posts: 9,500
  • Joined: 29-May 08

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 02:02 PM

Using the following Iterator to yield dates.
  Public Iterator Function YieldDates(d As Date, inc As Boolean) As IEnumerable(of  Date)
     Dim a = If(inc,-1,1)
     While True
         Yield d  
         d = d.AddDays(a)
    end While
  End Function


Then use LINQ. :shuriken:
  Public  Function AddWorkdays_C(d As date, wd As Integer) As Date
    Return ( From x in YieldDates( d, wd<0 )
            Where x.DayOfWeek <> DayOfWeek.Saturday
            Where x.DayOfWeek <> DayOfWeek.Sunday 
            Skip Math.Abs(wd)
            Take 1 ).FirstOrDefault        
  End Function


Which I :censored: like a lot.

This post has been edited by AdamSpeight2008: 04 May 2013 - 02:04 PM

Was This Post Helpful? 0
  • +
  • -

#19 andrewsw  Icon User is offline

  • It's just been revoked!
  • member icon

Reputation: 3836
  • View blog
  • Posts: 13,583
  • Joined: 12-December 12

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 02:09 PM

What no rep :)

In VBA Sunday is 1 and Saturday 7, and if we use the older Weekday() function we can specify what day the week starts on.

However, I hope that we could rely on the weekdays enumeration. Would MS have the gall to change it (again)?! >_<
Was This Post Helpful? 0
  • +
  • -

#20 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2271
  • View blog
  • Posts: 9,500
  • Joined: 29-May 08

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 02:20 PM

During this I discovered something which is counter-intuitive (to me).
Do 
  If conditon Then 
    Continue Do  
  End If
Loop Until exit_condition



You'd think it'll jump back to Do but it does not it jumps to the Loop Until. Doh?

This post has been edited by AdamSpeight2008: 04 May 2013 - 02:20 PM

Was This Post Helpful? 0
  • +
  • -

#21 andrewsw  Icon User is offline

  • It's just been revoked!
  • member icon

Reputation: 3836
  • View blog
  • Posts: 13,583
  • Joined: 12-December 12

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 02:26 PM

View PostAdamSpeight2008, on 04 May 2013 - 09:20 PM, said:

During this I discovered something which is counter-intuitive (to me).
Do 
  If conditon Then 
    Continue Do  
  End If
Loop Until exit_condition



You'd think it'll jump back to Do but it does not it jumps to the Loop Until. Doh?

That makes sense to me, otherwise you would use Exit Do.

This (final) version is neater:

    Public Function AddWorkDays(ByVal dte As Date, ByVal x As Integer) As Date
        Dim a As Integer = If(x < 0, -1, 1)
        Dim weekend = {DayOfWeek.Saturday, DayOfWeek.Sunday}
        While x <> 0 Or weekend.Contains(dte.DayOfWeek)
            dte = dte.AddDays(a)
            x -= If(x = 0 Or weekend.Contains(dte.DayOfWeek), 0, a)
        End While
        Return dte
    End Function

Added: In fact, it could be easily modified to incorporate an array of bank holidays.

This post has been edited by andrewsw: 04 May 2013 - 02:35 PM

Was This Post Helpful? 0
  • +
  • -

#22 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2271
  • View blog
  • Posts: 9,500
  • Joined: 29-May 08

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 02:34 PM

Still contains that annoy (to me) repetition, of the conditions checks.
The following has very little repetition, which appeases the don't repeat yourself feelings.

  Public Function AddWorkDays_D(d As Date, x As Integer) As Date
    Dim a = If(x<0,-1,1)  
    Beginning:
    If (d.DayOfWeek = DayOfWeek.Saturday) OrElse (d.DayOfWeek = DayOfWeek.Sunday)  Then GoTo NextDate  
    If x <> 0 Then GoTo ChangeX   
    Return D
    ChangeX:
      x -= a
    NextDate:
      d = d.AddDays(a)
      GoTo Beginning 
 End Function



Any issues with that one?
Was This Post Helpful? 0
  • +
  • -

#23 andrewsw  Icon User is offline

  • It's just been revoked!
  • member icon

Reputation: 3836
  • View blog
  • Posts: 13,583
  • Joined: 12-December 12

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 02:40 PM

Erm, GoTo?! Three labels :whatsthat: (spaghetti anyone?)

Seems a lot of effort to go through to avoid a minor piece of repetition(?).

This post has been edited by andrewsw: 04 May 2013 - 02:41 PM

Was This Post Helpful? 0
  • +
  • -

#24 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2271
  • View blog
  • Posts: 9,500
  • Joined: 29-May 08

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 02:46 PM

View Postandrewsw, on 04 May 2013 - 10:26 PM, said:

View PostAdamSpeight2008, on 04 May 2013 - 09:20 PM, said:

During this I discovered something which is counter-intuitive (to me).
Do 
  If conditon Then 
    Continue Do  
  End If
Loop Until exit_condition



You'd think it'll jump back to Do but it does not it jumps to the Loop Until. Doh?

That makes sense to me, otherwise you would use Exit Do.

If it work the way I thought it would, the following would be a valid entry.
Do
 If d.DayOfWeek = DayOfWeek.Saturday OrElse d.DayOfWeek = Sunday Then
    d = d.AddDays(a)
    Continue Do
 Else If x<> 0 Then
    d = d.AddDays(a)
    x -= a
    Continue Do
 End If
Loop Until x = 0



That be method localized spaghetti.

What about adding in checks for if the date d is on of min or max values for a date?
I'd only have to have in one place, not two.

This post has been edited by AdamSpeight2008: 04 May 2013 - 02:40 PM

Was This Post Helpful? 0
  • +
  • -

#25 andrewsw  Icon User is offline

  • It's just been revoked!
  • member icon

Reputation: 3836
  • View blog
  • Posts: 13,583
  • Joined: 12-December 12

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 02:46 PM

You could introduce a boolean flag:

Loop Until x = 0 And Not goAgain

(or make x nullable :))

This post has been edited by andrewsw: 04 May 2013 - 02:50 PM

Was This Post Helpful? 0
  • +
  • -

#26 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2271
  • View blog
  • Posts: 9,500
  • Joined: 29-May 08

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 03:18 PM

Likes so.
  Dim a = If(x<0, -1, 1)
  Do
    Dim GoAgain = True
    If (d.DayOfWeek = DayOfWeek.Saturday) OrElse (d.DayOfWeek = DayOfWeek.Sunday) Then
       d = d.AddDays(a)
    Else If x <> 0 Then
       d = d.AddDays(a)
       x -= a
    Else
       GoAgain = False
    End If
  Loop Until (x = 0) AndAlso Not (GoAgain)
  Return D


Is not valid syntax the GoAgain isn't in scope.
  Public Function AddWorkDays_E(d As Date, x As Integer) As Date
    Dim a = If(x<0, -1, 1)
    Dim GoAgain As Boolean 
    Do
      GoAgain = True 
      If (d.DayOfWeek = DayOfWeek.Saturday) OrElse (d.DayOfWeek = DayOfWeek.Sunday) Then
         d = d.AddDays(a)
      Else If x <> 0 Then
         d = d.AddDays(a)
         x -= a
      Else
        GoAgain = False
      End If
    Loop Until (x = 0) AndAlso Not (GoAgain)
    Return D
  End Function


then it could be postulated you don't need x = 0
 Public Function AddWorkDays_F(d As Date, x As Integer) As Date
    Dim a = If(x<0, -1, 1)
    Dim GoAgain As Boolean 
    Do
      GoAgain = True 
      If (d.DayOfWeek = DayOfWeek.Saturday) OrElse (d.DayOfWeek = DayOfWeek.Sunday) Then
         d = d.AddDays(a)
      Else If x <> 0 Then
         d = d.AddDays(a)
         x -= a
      Else
        GoAgain = False
      End If
    Loop While GoAgain
    Return D
  End Function



I'm a advocate of the style, that they should only be a single condition for conditional part of looping constructs.
Multiple conditions suggest it need to be simplified. And stylistically it look complex and untidy.
Was This Post Helpful? 0
  • +
  • -

#27 andrewsw  Icon User is offline

  • It's just been revoked!
  • member icon

Reputation: 3836
  • View blog
  • Posts: 13,583
  • Joined: 12-December 12

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 03:27 PM

You don't need to keep resetting GoAgain to True (and I still like Contains() :)/>).

    Public Function AddWorkDays_F(ByVal d As Date, ByVal x As Integer) As Date
        Dim a = If(x < 0, -1, 1)
        Dim GoAgain As Boolean = True
        Do
            If {DayOfWeek.Saturday, DayOfWeek.Sunday}.Contains(d.DayOfWeek) Then
                d = d.AddDays(a)
            ElseIf x <> 0 Then
                d = d.AddDays(a)
                x -= a
            Else
                GoAgain = False
            End If
        Loop While GoAgain
        Return D
    End Function

This post has been edited by andrewsw: 04 May 2013 - 03:34 PM

Was This Post Helpful? 0
  • +
  • -

#28 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2271
  • View blog
  • Posts: 9,500
  • Joined: 29-May 08

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 03:36 PM

.Contains is backwards when being read, especially if is a single value.
So I like to use the .IsAnyOfThese extension method
  <Extension>
  Function IsAnyOfThese(Of T As IComparable)(Value As T, These As IEnumerable(Of T)) As Boolean
    Return These.Any(Function(x) x.CompareTo(Value) = 0)
  End Function


As it so much easier to read and understand when look at the code.
If d.DayOfWeek.IsAnyOfThese( { Saturday, Sunday } ) Then


This post has been edited by AdamSpeight2008: 04 May 2013 - 03:45 PM

Was This Post Helpful? 0
  • +
  • -

#29 andrewsw  Icon User is offline

  • It's just been revoked!
  • member icon

Reputation: 3836
  • View blog
  • Posts: 13,583
  • Joined: 12-December 12

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 03:38 PM

Yes, Contains() is backwards, he,he! :)

Added: What happeneded to IN() ? I wouldn't mind having this as an extension method. I suppose I could just replace IsAnyOfThese with In in the above code.

This post has been edited by andrewsw: 04 May 2013 - 03:47 PM

Was This Post Helpful? 0
  • +
  • -

#30 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2271
  • View blog
  • Posts: 9,500
  • Joined: 29-May 08

Re: Challenge: Un-Recursive (Simple?)

Posted 04 May 2013 - 03:59 PM

Using Exts.Dates makes it a little better.

  Public Function AddWorkDays_E(d As Date, x As Integer) As Date
    Dim a = If(x<0, -1, 1)
    Dim GoAgain =True 
    Do
      If d.IsA(Saturday) Or d.IsA(Sunday) Then
         d = d.AddDays(a)
      Else If x <> 0 Then
         d = d.AddDays(a)
         x -= a
      Else
        GoAgain = False
      End If
    Loop While GoAgain
    Return D
  End Function



May have to add .IsAnyOfThese to a Exts package? :fuck-8: thou I'm sure it I had it anyways.
Added to and Updated: Exts.IEnumerable
Was This Post Helpful? 0
  • +
  • -

  • (4 Pages)
  • +
  • 1
  • 2
  • 3
  • 4