пользовательская функция, не принимающая аргументы с rlang:: enquo

Я пишу пользовательскую функцию, которая требует создания фрейма данных из введенных аргументов. Я хочу, чтобы пользователи разрешали два разных способа ввода аргументов. Как вы можете видеть ниже, работает один из способов, но не тот, который опирается на rlang.

Идея состоит в том, что я хочу предоставить пользователю функции как можно больше гибкости, поэтому необязательный аргумент и два разных метода ввода аргумента.

Вот воспроизводимый код:

# loading libraries
library(dplyr)
library(rlang)
library(datasets)

# preparing the dataset
iris <- datasets::iris
iris$newvar <- 1:length(iris$Sepal.Length)
str(iris)
#> '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 ...
#>  $ newvar      : int  1 2 3 4 5 6 7 8 9 10 ...

# defining the custom function
myfun <- function(data = NULL, x, y, z = NULL) {
  if (!is.null(data)) {
    if (!is.null(z)) {
      data <-
        dplyr::select(
          .data = data,
          x = !!rlang::enquo(x),
          y = !!rlang::enquo(y),
          z = !!rlang::enquo(z)
        )
    } else {
      data <-
        dplyr::select(
          .data = data,
          x = !!rlang::enquo(x),
          y = !!rlang::enquo(y)
        )
    }
  } else {
    if (!is.null(z)) {
      data <-
        base::cbind.data.frame(x = x,
                               y = y,
                               z = z)
    } else {
      data <- base::cbind.data.frame(x = x,
                             y = y)
    }
  }

  print(str(data))

}

# method 1
# using the custom fuction without the optional argument
myfun(x = iris$Species, y = iris$Sepal.Length)
#> 'data.frame':    150 obs. of  2 variables:
#>  $ x: Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
#>  $ y: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> NULL

# using the custom fuction with the optional argument
myfun(x = iris$Species, y = iris$Sepal.Length, z = iris$newvar)
#> 'data.frame':    150 obs. of  3 variables:
#>  $ x: Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
#>  $ y: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#>  $ z: int  1 2 3 4 5 6 7 8 9 10 ...
#> NULL

# method 2
# using the custom fuction without the optional argument
myfun(data = iris, x = Species, y = Sepal.Length)
#> 'data.frame':    150 obs. of  2 variables:
#>  $ x: Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
#>  $ y: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> NULL
# using the custom fuction with the optional argument
myfun(data = iris,
      x = Species,
      y = Sepal.Length,
      z = newvar)
#> Error in myfun(data = iris, x = Species, y = Sepal.Length, z = newvar): object 'newvar' not found

Создано 2 февраля 2018 г. с помощью пакета reprex (v0.1.1.9000).


person Indrajeet Patil    schedule 02.02.2018    source источник
comment
Возможный дубликат: stackoverflow.com/q/48504942/2372064   -  person MrFlick    schedule 03.02.2018
comment
@MrFlick ДА!!! Это решило проблему. Благодаря тонну!!   -  person Indrajeet Patil    schedule 04.02.2018
comment
@MrFlick Как мне принять ваш ответ? Это не показывает мне возможности принять ваш комментарий как правильный ответ.   -  person Indrajeet Patil    schedule 04.02.2018
comment
Так как это в основном дубликат. Я могу просто закрыть этот вопрос как дубликат. Вы можете проголосовать за мой ответ на другой вопрос, если хотите.   -  person MrFlick    schedule 04.02.2018
comment
@MrFlick Готово! Спасибо.   -  person Indrajeet Patil    schedule 04.02.2018


Ответы (1)


Похоже, тест !is.null(z)) не работает. Он пытается интерпретировать z, но для z задано имя newvar, и вызов is.null не может его интерпретировать, поскольку объект newvar не найден.

Вместо этого попробуйте это:

!is.null(quo(z)))
person Edward Carney    schedule 02.02.2018
comment
Спасибо за предложение. Кажется, это решает проблему, с которой я сталкиваюсь, но создает другую проблему. Если я сейчас ввожу: myfun(data = iris, x = Species, y = Sepal.Length), выдает следующую ошибку: Error: NULL must resolve to integer column positions, not NULL - person Indrajeet Patil; 03.02.2018
comment
Интересная проблема. Если вы удалите присваивание NULL для z в определении, myfun(data = iris, x = Species, y = Sepal.Length) будет работать. Но тогда другая форма вызова не работает. Хм. - person Edward Carney; 03.02.2018