title: `purrr` alternative to row-wise function that determines event date based on complex rule set
body: <p>I am working with a client that wants to provide an input spreadsheet with a text description of when certain events should occur in a given year. Each event (and there are at least 200 of them) is a separate row, containing a complex rule set about when it should occur, e.g., <em>&quot;the first Saturday before October 1st&quot;</em> or <em>&quot;the Friday closest to December 1st&quot;</em>. There are also a few times when the event simply occurs on a particular date, but this is rare. However, the actual spreadsheet has about 15 columns that control the start dates of each event, so the logic I need to use to compute the start dates gets pretty in-depth.</p>
  <p>I've come up with a way to compute the start dates using a function and a loop that iterates over each row of my <code>data.frame</code>, but I'm wondering whether there is a more efficient <code>tidyverse</code> or <code>purrr</code> solution to this problem. Is it possible (or advisable) to vectorize a solution to this problem?</p>
  <p>This is my current (working) solution for the smallest, most compact example I could imagine. Can I make this more efficient, and readable for my more complex real-world input?</p>
  <pre><code>library(tidyverse)
  library(lubridate)
  
  # Bring in demo data that describes 3 events, and when they should each start.
  
  demo &lt;- structure(list(Event = c(&quot;Gala&quot;, &quot;Celebration&quot;, &quot;Wrap-up&quot;), date_start
  = structure(c(18871, NA, NA), class = &quot;Date&quot;), weekday_near = c(NA,
  &quot;Saturday&quot;, &quot;Friday&quot; ), near_description = c(NA, &quot;before&quot;, &quot;closest to&quot;),
  near_date = structure(c(NA, 18901, 18962), class = &quot;Date&quot;)), row.names = c(NA,
  -3L), class = c(&quot;tbl_df&quot;, &quot;tbl&quot;, &quot;data.frame&quot;))
  </code></pre>
  <p>This is what the <code>demo</code> data look like:</p>
  <pre><code>Event       date_start weekday_near near_description near_date 
  Gala        2021-09-01 NA           NA               NA        
  Celebration NA         Saturday     before           2021-10-01
  Wrap-up     NA         Friday       closest to       2021-12-01
  </code></pre>
  <p>Now, determine start dates for each event - the Gala, the Celebration, and the Wrap-up.</p>
  <pre><code># Create a tibble that contains all possible dates for these events this year.
  
  datedb &lt;- tibble(date = seq(make_date(2021, 9, 1), make_date(2021, 12, 31), by = 1),
                   wday = wday(date, label = TRUE, abbr = FALSE))
  
  
  # Write function meant to determine event date for each row of the dataframe.
  
  determine_date &lt;- function(df){
    
    # define variables that are easier to read
    # this part makes me squeamish - 
    # there's gotta be a better way to do this with the tidyverse
    event_date_exact &lt;- df[[&quot;date_start&quot;]]
    event_near_wday &lt;- df[[&quot;weekday_near&quot;]]
    event_near_desc &lt;- df[[&quot;near_description&quot;]]
    event_near_date &lt;- df[[&quot;near_date&quot;]]
    
    # Event date - if there is an exact date for the event, choose it as the event date.
    if (!is.na(event_date_exact)) {
      event_date &lt;- event_date_exact
    
    # Otherwise, if the date is dependent on another date, figure out when it should be:
    } else {
      event_date_vec &lt;- datedb %&gt;% filter(wday == event_near_wday) %&gt;% pull(date)
      event_date &lt;- 
        case_when(
          # If you're looking for the closest weekday to a particular date:
          event_near_desc == &quot;closest to&quot; ~ event_date_vec[which(abs(event_date_vec - event_near_date) == 
                           min(abs(event_date_vec - event_near_date), na.rm = TRUE))],
          # If you're looking for the first weekday before that weekday
          event_near_desc == &quot;before&quot; ~ rev(event_date_vec[which(event_date_vec - event_near_date &lt; 0)])[1],
          # If neither of these worked, output NA to check why 
          TRUE ~ NA_Date_
        )
         }
  }
  
  # create empty vector to store results
  start_dates &lt;- lubridate::ymd()
  
  for (i in 1:nrow(demo)) {
    start_dates[i] &lt;- determine_date(demo[i,])
  }
  
  # add start dates back to original demo dataframe
  demo$start_date &lt;- start_dates
  </code></pre>
  <h3>Desired output:</h3>
  <p>Note new <code>start_date</code> column</p>
  <pre><code>demo
  
  Event       date_start weekday_near near_description near_date    start_date
  Gala        2021-09-01 NA           NA               NA           2021-09-01
  Celebration NA         Saturday     before           2021-10-01   2021-09-25
  Wrap-up     NA         Friday       closest to       2021-12-01   2021-12-03
  </code></pre>