7

I'm getting an error trying to compare and set weekday string values as either a "weekend" or a "weekday" using R. Any suggestions on how to approach this problem in a better way would be great.

x <- c("Mon","Tue","Wed","Thu","Fri","Sat","Sun")

setDay <- function(day){
          if(day == "Sat" | "Sun"){
           return("Weekend")
          } else { 
            return("Weekday")
          }
        }

sapply(x, setDay)

This is the error I get back in RStudio:

Error in day == "Sat" | "Sun" : 
  operations are possible only for numeric, logical or complex types
Bridgbro
  • 269
  • 1
  • 3
  • 17

1 Answers1

15

Instead of using sapply to loop through each individual day in x and check whether it's the weekday or weekend, you can do this in a single vectorized operation with ifelse and %in%:

ifelse(x %in% c("Sat", "Sun"), "Weekend", "Weekday")
# [1] "Weekday" "Weekday" "Weekday" "Weekday" "Weekday" "Weekend" "Weekend"

The motivation for using vectorized operations here is twofold -- it will save you typing and it will make your code more efficient.

josliber
  • 43,891
  • 12
  • 98
  • 133
  • 1
    And as a counter to the `ifelse` hate: `c("Weekend", "Weekday")[1L+x %in% c("Sat", "Sun")]` – Frank Aug 11 '15 at 18:03
  • 6
    @Frank I understand the motivation for that sort of expression instead of `ifelse`, but I find it to be a lot less readable. – josliber Aug 11 '15 at 18:04
  • ^^ especially the `1L` - is that even necessary? – Señor O Aug 11 '15 at 18:05
  • 4
    I'm with you; just trying to guard against an unnecessary answer with that approach :) – Frank Aug 11 '15 at 18:06
  • @SeñorO you add the 1 to convert `FALSE` and `TRUE` to indices 1 and 2, respectively. – josliber Aug 11 '15 at 18:06
  • Yeah, but the `L` specifies that it's an integer, which is used sometimes in highly optimized code, which this doesn't need to be. I think `[1 + x %in% c(...)]` would be more readable? – Señor O Aug 11 '15 at 18:08
  • Ah gotcha, you're saying 1L versus 1. I also noticed in this particular case that it should be `c("Weekday", "Weekend")[1L+x %in% c("Sat", "Sun")]` instead (flip the first vector). – josliber Aug 11 '15 at 18:09
  • `ifelse("Sunday" %in% c("Sat", "Sun"), "Weekend", "Weekday")` – ExperimenteR Aug 11 '15 at 18:10
  • @ExperimenteR well, from the question it seems like it's going to be "Sun" instead of "Sunday" -- note that the OP's original code (with the bug fix) will also return "Weekday" in this case. Of course, you could defend against the fully spelled days by checking for inclusion in the set `c("Sat", "Sun", "Saturday", "Sunday")`. – josliber Aug 11 '15 at 18:12
  • 2
    also, if `%in%` syntax confuses you, you can use `is.element()` (although takes up more characters) – rbatt Aug 11 '15 at 18:15
  • 1
    Once we start allowing Sunday, Saturday, Sat, etc., it's time to regex: `ifelse(grepl("sun|sat",tolower(x)),"Weekend","Weekday")` – MichaelChirico Aug 11 '15 at 18:22
  • 1
    For the uninitiated, "the motivation for that sort of expression" is [here](http://stackoverflow.com/questions/16275149/does-ifelse-really-calculate-both-of-its-vectors-every-time-is-it-slow) – MichaelChirico Aug 11 '15 at 19:16