Search code examples
rtidyverse

Change numeric(0) to NA in pipe, but return unchanged otherwise


How to recode vector to NA if it is zero length (numeric(0)), but return the vector unchanged if not? Preferably in tidyverse using pipes.

My attempt:

library(tidyverse)
empty_numeric <- numeric(0)
empty_numeric |> 
    if_else(length(.) > 0, true =  NA, false = . )
#> Error: `condition` must be a logical vector, not a double vector.

Solution

  • You can’t use a vectorised if_else here because its output is the same length as its input (i.e. always a single element). Instead, you’ll need to use conventional if. And neither will work with the built-in |> pipe since that restricts how the call can be formed (in particular, it only allows substituting the LHS into top-level arguments, and only once). By contrast, we need to repeat the LHS, and substitute it into a nested expression.

    Using the ‘magrittr’ pipe operator works, however:

    myvec %>% {if (length(.) > 0L) . else NA}
    

    Or, if you prefer writing this using function call syntax:

    myvec %>% `if`(length(.) > 0L, ., NA)
    

    To be able to use the native pipe, we need to wrap the logic into a function:

    na_if_null = function (x) {
        if (length(x) == 0L) as(NA, class(x)) else x
    }
    
    myvec |> na_if_null()
    

    (The as cast is there to ensure that the return type is the same as the input type, regardless of the type of x.)