user1206480
user1206480

Reputation: 1858

Using F# match to extract two days out of the week

Learning to use F#, and I'm trying to get familiar with the match expression. I expect the below code to pick two consecutive days out of the week, the current day and the day after. It only picks out the current day. What am I missing here?

DayOfWeek array:

let days = [|DayOfWeek.Sunday, true; 
             DayOfWeek.Monday, false; 
             DayOfWeek.Tuesday, true;
             DayOfWeek.Wednesday, true; 
             DayOfWeek.Thursday, true; 
             DayOfWeek.Friday, true; 
             DayOfWeek.Saturday, true;|]

Match expression:

 let curDate = DateTime.Now
 let validDates = 
        [
            for i in days do
            match i with
            | day, true ->
                match day with
                | x when int x = int curDate.DayOfWeek || 
                    int x > int curDate.DayOfWeek
                    && int x - int curDate.DayOfWeek = 1 ->
                    yield
                        x
                | _ -> ()
            |_ -> ()
        ]

Upvotes: 0

Views: 417

Answers (3)

Troy Kershaw
Troy Kershaw

Reputation: 590

For me, the difficulty is with using pattern matching.

Here is how I would do it without, allowing you to take any number of days, not just two.

open System

let next count days day =
    seq { while true do yield! days } // make the days array infinite
    |> Seq.skipWhile (fun (d, _) -> d <> day) // skip until we find our day
    |> Seq.filter (fun (_, incl) -> incl) // get rid of 'false' days
    |> Seq.take count // take the next 'count' of days
    |> Seq.map (fun (d, _) -> d) // we only care about the day now, so a simple map gets rid of the boolean

Using your array of days, I get the following:

DayOfWeek.Sunday
|> next 2 days

val it : seq<DayOfWeek> = seq [Sunday; Tuesday]

and

DayOfWeek.Thursday
|> next 3 days

val it : seq<DayOfWeek> = seq [Thursday; Friday; Saturday]

and

DayOfWeek.Sunday
|> next 10000 days
|> Seq.iter (printfn "%A")

Well, I'm not going to print what this one does, you'll just have to use your imagination. :)

I hope that helps!

Edit I made it handle an infinite number of days.

Upvotes: 1

Random Dev
Random Dev

Reputation: 52290

I think you can write this a lot easier by using the Enum-caps of F#/.net:

open System;;

let weekdayAfter (day : DateTime) : DayOfWeek = 
    int day.DayOfWeek
    |> (fun i -> (i+1) % 7) 
    |> Microsoft.FSharp.Core.LanguagePrimitives.EnumOfValue<_, _>                 

let today_and_tomorrow = 
   let today = DateTime.Today
   (today.DayOfWeek, weekdayAfter today)

And if you really want to use pattern-matching then why not go with the readable/obvious solution:

let dayAfter (day : DateTime) =
    match day.DayOfWeek with
    | DayOfWeek.Sunday    -> DayOfWeek.Monday
    | DayOfWeek.Monday    -> DayOfWeek.Tuesday
    | DayOfWeek.Tuesday   -> DayOfWeek.Wednesday
    | DayOfWeek.Wednesday -> DayOfWeek.Thursday
    | DayOfWeek.Thursday  -> DayOfWeek.Friday
    | DayOfWeek.Friday    -> DayOfWeek.Saturday
    | DayOfWeek.Saturday  -> DayOfWeek.Sunday
    | _                   -> failwith "should never happen"

Upvotes: 1

king jah
king jah

Reputation: 258

Your solution seems extremely convoluted to me, and like others have mentioned it only works if the underlying int value of tomorrow's DayOfWeek is one greater than today's. As you know, the week is a cycle so that logic won't always hold true. I don't want to spoonfeed, but there is a much easier solution:

let today = DateTime.Now.DayOfWeek

let days = [|DayOfWeek.Sunday, true; 
             DayOfWeek.Monday, false; 
             DayOfWeek.Tuesday, true;
             DayOfWeek.Wednesday, true; 
             DayOfWeek.Thursday, true; 
             DayOfWeek.Friday, true; 
             DayOfWeek.Saturday, true;|]

let today_and_tomorrow =
    let idx_today = Array.findIndex (fun (day, _) -> day = today) days
    days.[idx_today], days.[idx_today + 1 % days.Length]

Upvotes: 3

Related Questions