Reputation: 1372
I have a character vector r <- c()
. I want to mutate on dataframe based on length of r
This works
iris %>% if(length(r) > 0) mutate(Test = 1) else .
This does not work when I expand to add more dplyr verbs
iris %>% if(length(r) > 0) mutate(Test = 1) else . %>% mutate(Test2 = 1)
I am only looking for dplyr based solution.
Upvotes: 4
Views: 267
Reputation: 1396
library(dplyr)
Using an intermediate function provides an alternative solution once it is substituted by an anonymous function
g_if <- function(df, r){
if(length(r)) {
ans <- df %>% mutate(test = 1)
} else {
ans <- df
}
invisible(ans)
}
r <- c()
iris %>% g_if(r) %>% str
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
r <- c(1)
iris %>% g_if(r) %>% str
#> 'data.frame': 150 obs. of 6 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
#> $ test : num 1 1 1 1 1 1 1 1 1 1 ...
Now, we can use the same idea with an anonymous function, that is, without defining explicitely
function g_if()
r <- c()
iris %>% {
function(df, cond){
if(length(cond) > 0) {
ans <- df %>% mutate(test = 1)
} else {
ans <- df
}
ans}}(r) %>%
head
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 5.1 3.5 1.4 0.2 setosa
#> 2 4.9 3.0 1.4 0.2 setosa
#> 3 4.7 3.2 1.3 0.2 setosa
#> 4 4.6 3.1 1.5 0.2 setosa
#> 5 5.0 3.6 1.4 0.2 setosa
#> 6 5.4 3.9 1.7 0.4 setosa
r <- c(1)
iris %>% {
function(df, cond){
if(length(cond) > 0) {
ans <- df %>% mutate(test = 1)
} else {
ans <- df
}
ans}}(r) %>%
head
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species test
#> 1 5.1 3.5 1.4 0.2 setosa 1
#> 2 4.9 3.0 1.4 0.2 setosa 1
#> 3 4.7 3.2 1.3 0.2 setosa 1
#> 4 4.6 3.1 1.5 0.2 setosa 1
#> 5 5.0 3.6 1.4 0.2 setosa 1
#> 6 5.4 3.9 1.7 0.4 setosa 1
Created on 2021-06-17 by the reprex package (v0.3.0)
Upvotes: 2
Reputation: 31
The below code will add the variable if the condition is met. If not, it will add a variable populated will all NA and eventually remove it (I understand you need the new variable only if the condition is met).
library(dplyr)
r <- c()
iris %>%
mutate(test2=if_else(length(r)>0, 2, NULL)) %>%
select(where(~ !(all(is.na(.))))) #remove columns with all NAs
Upvotes: 0
Reputation: 887851
As there are multiple statements, wrap it inside a {}
r <- c()
iris %>%
{if(length(r) > 0) {
mutate(., Test = 1)
} else .}
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
...
-testing with r
length > 0
r <- 5
iris %>%
{if(length(r) > 0) {
mutate(., Test = 1)
} else .}
Sepal.Length Sepal.Width Petal.Length Petal.Width Species Test
1 5.1 3.5 1.4 0.2 setosa 1
2 4.9 3.0 1.4 0.2 setosa 1
3 4.7 3.2 1.3 0.2 setosa 1
...
However, this can be easily modified without a loop i.e. convert the logical vector to numeric index by adding 1 (as indexing in R
starts from 1). Use that to select a list
with values 1 and NULL. If the length is 0, then NULL is selected and thus no column is created
iris %>%
mutate(Test = list(NULL, 1)[[1 + (length(r) > 0)]])
Upvotes: 3
Reputation: 79204
We could use ifelse
library(dplyr)
r <- c()
iris %>%
mutate(Test = ifelse(length(r) > 0, 1,1))
Output:
Sepal.Length Sepal.Width Petal.Length Petal.Width Species Test
1 5.1 3.5 1.4 0.2 setosa 1
2 4.9 3.0 1.4 0.2 setosa 1
3 4.7 3.2 1.3 0.2 setosa 1
4 4.6 3.1 1.5 0.2 setosa 1
5 5.0 3.6 1.4 0.2 setosa 1
6 5.4 3.9 1.7 0.4 setosa 1
Upvotes: 0