0

I'm trying to create a function that receives a word and returns a number based in which group that word belongs to, I've created the following function, which only works with single inputs:

get_humor <- function(x) {

  feeling <- str_to_lower(x)

  if (x %in% group5) return(5)
  if (x %in% group4) return(4)
  if (x %in% group3) return(3)
  if (x %in% group2) return(2)
  if (x %in% group1) return(1)


}

I know that I can use nested ifelses, like this:

ifelse(x %in% nv5, 5, 
         ifelse(x %in% nv4, 4,
                ifelse(x %in% nv3, 3,
                       ifelse(x %in% nv2, 2, 1))))

But there is a way to make a vectorized version of this function without using other auxiliary functions, like lapply() or Vectorize()?

  • `sapply(word_list, FUN = function(x) ifelse(x %in% nv5, 5, ifelse(x %in% nv4, 4, ifelse(x %in% nv3, 3, ifelse(x %in% nv2, 2, 1)))))` should do the trick. `ifelse` _is_ vectorized, but you're probably running into issues with logical recycling, if you compare a vector `x` to another with `%in%` – bouncyball Dec 17 '19 at 13:54
  • 3
    Maybe `dplyr::case_when()` – Dave2e Dec 17 '19 at 13:55
  • In order to vectorize, you should use a list of groups:`groups <- list(group1, group2, ..., group5)` – asachet Dec 17 '19 at 13:58
  • 2
    Please provide a reproducible example. I think you could vectorize this with a single `match` statement – David Arenburg Dec 17 '19 at 14:05
  • Suggested duplicate: [dictionary-style replacement](https://stackoverflow.com/q/7547597/903061) – Gregor Thomas Dec 17 '19 at 14:11

2 Answers2

0

Here is an option. The key is to store your groups in a list over which you can loop/apply/map.

groups <- list(group1, group2, group3, group4, group5)

# Using apply
get_humor <- function(x, groups) {
  x_in <- sapply(groups, function(g) x %in% g)
  max(which(x_in))
}

# Using purrr
get_humor <- function(x, groups) {
  x_in <- purrr::map_lgl(groups, function(g) x %in% g)
  max(which(x_in))
}

This checks which groups x belongs to and returns the highest group index.

Another option is to return as soon as a group is found. This can be done with a for loop but also with detect_index from purrr which does just that in a one-liner.

purrr::detect_index(groups, ~ x %in% ., .dir = "backwards")

Note by default detect_index will return the first index at which the predicate is true. Since you want the last index, you need to specify .dir = "backwards".

asachet
  • 6,620
  • 2
  • 30
  • 74
0

This is one of the examples where a for loop actually makes sense in R, because you don't want a list of all possible return values and if you found the right one you don't need the other ones. So, how 'bout this:

get_humor <- function(x, groupList)
    for (i in seq_along(groupList)){
        if (x %in% groupList[[i]]) return(i)
    }
}
Georgery
  • 7,643
  • 1
  • 19
  • 52