Home > Enterprise >  ifelse assignment does not return pre-defined character vector
ifelse assignment does not return pre-defined character vector

Time:04-23

I cannot figure out why an ifelse assignment does not return the entire object I'm trying to pass.

Below, I look to see if the state of Texas is in a vector of state names (in my actual code, I'm looking up unique state names in a shapefile). Then, if Texas is in this list of state names, assign to a new object (states_abb) the abbreviations for Texas and New Mexico. Otherwise, assign to states_abb the abbreviations for California and Nevada.

I know from this post and ?ifelse that...

ifelse returns a value with the same shape as test which is filled with elements selected from either yes or no depending on whether the element of test is TRUE or FALSE.

So in my first example below, I can understand that only CA is returned.

states <- c("California", "Nevada")
(states_abb <- ifelse("Texas" %in% states, c("NM", "TX"), c("CA", "NV")))
# [1] "CA"

But in this second example below, I've pre-defined the object canv_abb. Why doesn't that whole object get passed? Even if it's a character vector, it's its own object, right? Shouldn't that whole "package" get passed?

txnm_abb <- c("NM", "TX")
canv_abb <- c("CA", "NV")
(states_abb <- ifelse("Texas" %in% states, txnm_abb, canv_abb))
# [1] "CA"

I appreciate any insights as to why this is happening. And can someone offer a solution so that I can assign BOTH abbreviations?

CodePudding user response:

The key word here is 'same length'. If you apply ifelse both the input and output must have same length. In your case it is 1:2. In this case only the first will be calculated.

See ?ifelse: 'ifelse returns a value with the same shape as test"

solution use a classic if else structure:

states <- c("California", "Nevada")

states_abb <- if ("Texas" %in% states) {
  c("NM", "TX")
} else {
  c("CA", "NV")
}
> states_abb
[1] "CA" "NV"

CodePudding user response:

ifelse is the wrong tool here. You use ifelse when you have a vector of logical tests and you wish to create a new vector of the same length. You have a single logical test, but want your output to be a vector.

What you are describing is better handled by an if and else clause:

states_abb <- if("Texas" %in% states) txnm_abb else canv_abb

states_abb
#> [1] "CA" "NV"

To try to get a feel for how ifelse works, consider the following input and output:

condition <- c(TRUE, FALSE, FALSE)
input1    <- c("A", "b", "C")
input2    <- c("1", "2", "3")

result <- ifelse(condition, input1, input2)

result
#> [1] "A" "2" "3"

You will see that ifelse is a vectorized, shorthand way of writing the following loop, which is a pattern that comes up surprisingly often in data wrangling:

result <- character(3)

for(i in 1:length(condition)) {
  result[i] <- if(condition[i]) input1[i] else input2[i]
}

result
#> [1] "A" "2" "3"

Note though that this is not what you are trying to do in your own code.

  • Related