'Conditional assignment of vector in R

I'd like to assign a vecotr based on a conditional statement. How do I do this? This is what I have tried:

zero_rows <- ifelse(i == 1, c(2,3,4,7,12),
               ifelse(i == 2, c(4,7,12),
               ifelse(i == 3, c(2,3,4,7,9,12),
               ifelse(i == 4, c(4,7,9),
               ifelse(i == 5, c(4,12),
               ifelse(i == 6, c(9,12),
               ifelse(i == 7, 12,
               ifelse(i == 8, c(2,3,4,7,9,12), 0))))))))

and


  zero_rows <- case_when(i == 1 ~ c(2,3,4,7,12),
                         i == 2 ~ c(4,7,12),
                         i == 3 ~ c(2,3,4,7,9,12),
                         i == 4 ~ c(4,7,9),
                         i == 5 ~ c(4,12),
                         i == 6 ~ c(9,12),
                         i == 7 ~ 12,
                         i == 8 ~ c(2,3,4,7,9,12),
                         TRUE ~ 0)


Solution 1:[1]

It may be a case for switch

fn <- function(i) {
   i <- as.character(i)
   switch(i, 
         "1" = c(2,3,4,7,12),
          "2" = c(4,7,12),
          "3" = c(2,3,4,7,9,12),
          "4" = c(4,7,9),
          "5" = c(4,12),                              
          "6" = c(9,12),
          "7" = 12,
          "8" = c(2,3,4,7,9,12), 
         0)


}

-testing

> fn(1)
[1]  2  3  4  7 12
> fn(2)
[1]  4  7 12
> fn(3)
[1]  2  3  4  7  9 12
> fn(9)
[1] 0
> fn(10)
[1] 0

If we want to do this on each value of a column ('col1'), use rowwise and wrap the output in a list

library(dplyr)
df1 %>%
    rowwise %>%
    mutate(out = list(fn(col1)))

Or with map

library(purrr)
df1 %>%
     mutate(out = map(col1, fn))

ifelse/if_else/case_when - expects all the arguments to be of same length. Based on the code showed, it is not the case where the length differ based on the input arguments

Solution 2:[2]

We can try nested ifelse along with list like below

f <- function(i) {
    ifelse(i == 1, list(c(2, 3, 4, 7, 12)),
        ifelse(i == 2, list(c(4, 7, 12)),
            ifelse(i == 3, list(c(2, 3, 4, 7, 9, 12)),
                ifelse(i == 4, list(c(4, 7, 9)),
                    ifelse(i == 5, list(c(4, 12)),
                        ifelse(i == 6, list(c(9, 12)),
                            ifelse(i == 7, list(12),
                                ifelse(i == 8, list(c(2, 3, 4, 7, 9, 12)), 0)
                            )
                        )
                    )
                )
            )
        )
    )[[1]]
}

Solution 3:[3]

It would be most natural to use i as an index, like so:

l <- list(c(2, 3, 4, 7, 12),
          c(4, 7, 12),
          c(2, 3, 4, 7, 9, 12),
          c(4, 7, 9),
          c(4, 12),
          c(9, 12),
          12,
          c(2, 3, 4, 7, 9, 12))

zero_rows <- ifelse(i %in% seq_along(l), l[i], list(0))

Though it would be safer and faster to avoid ifelse altogether:

ok <- i %in% seq_along(l)
zero_rows <- rep.int(list(0), length(i))
zero_rows[ok] <- l[i[ok]]

The first approach assumes that the elements of i are all greater than or equal to 1. The second approach supports any numeric i.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 ThomasIsCoding
Solution 3