Определите операторы с более чем 2 аргументами

Мне интересно, есть ли способ передать оператору более двух аргументов, или у меня нет другого выбора, кроме как использовать формат функции! Например, я мог бы определить оператор слияния, для которого требуется более 2 аргументов.

Вот просто пример, меня не интересует функциональность слияния:

1. Я сделал оператор для объединения двух фреймов данных с их общими именами столбцов A%>>%B:

`%>>%`<- function(a,b){
      by.tmp = intersect(names(a),names(b))
      base::merge(a,b,by = by.tmp)
}

2. Теперь я ищу способ определить, какой столбец должен соответствовать от data.frame A до data.frame B, например:

A %column_name_a>>column_name_b% B
# or feeding 2 arg from each side to operator like follow 
# which inside parenthesis return another operator
A (column_name_a %>>% column_name_b) B
# or more advanced
A:column_name_list_a%>>%column_name_list_b:B

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

ОБНОВЛЕНИЕ: мне удалось исправить оператор с неизвестным количеством аргументов (это своего рода каскад, но он работает). вот подход:

`%>%` <- function(a,b){

  ifvalid <- function(a, frame = parent.frame()){
    res = try(eval(a,frame),silent = T)
    flag = inherits(res, "try-error") | (length(res)==0)
    ifelse ((!flag) | (length(a)==1) , return(res),  return(
      lapply(a, ifvalid,frame=frame)
      )
    )
  }


  left_arg = substitute(a)
  right_arg= substitute(b)

  res = list(
    left = ifvalid(left_arg),
    right = ifvalid(right_arg)
  )

  return(res)
}

Пример запуска:

"X":1:NULL %>% date():`*`
# $left
# $left[[1]]
# .Primitive(":")
# 
# $left[[2]]
# $left[[2]][[1]]
# .Primitive(":")
# 
# $left[[2]][[2]]
# [1] "X"
# 
# $left[[2]][[3]]
# [1] 1
# 
# 
# $left[[3]]
# list()
# 
# 
# $right
# $right[[1]]
# .Primitive(":")
# 
# $right[[2]]
# [1] "Wed Feb 03 16:04:17 2016"
# 
# $right[[3]]
# function (e1, e2)  .Primitive("*")

person Mahdi Jadaliha    schedule 02.02.2016    source источник
comment
Передайте второму элементу вашему оператору список с фреймом данных в качестве первого элемента, а имена столбцов - в качестве второго элемента.   -  person IRTFM    schedule 03.02.2016
comment
Двоичные операторы по определению не может иметь более двух аргументов. В R нет тернарного оператора, но его создали другие .   -  person Joshua Ulrich    schedule 03.02.2016
comment
Спасибо Джошуа Ульрих. ваш комментарий очень помог. В упомянутом вами сообщении был ответ, который может помочь сделать оператор с любым количеством аргументов: stackoverflow.com/a/8792474/3019570< /а>   -  person Mahdi Jadaliha    schedule 03.02.2016


Ответы (1)


Иллюстрируя подход, изложенный выше в комментарии:

 `%>>%`<- function(a,b){
             base::merge(a,b[[1]],by = b[[2]])
 }

 authors %>>% list(books, "name")
 #-------
      name nationality deceased                         title other.author
1   McNeil   Australia       no     Interactive Data Analysis         <NA>
2   Ripley          UK       no            Spatial Statistics         <NA>
3   Ripley          UK       no         Stochastic Simulation         <NA>
4  Tierney          US       no                     LISP-STAT         <NA>
5    Tukey          US      yes     Exploratory Data Analysis         <NA>
6 Venables   Australia       no Modern Applied Statistics ...       Ripley

Используемая дата представляет собой слегка упрощенную версию кода на странице справки ?merge:

authors <- data.frame(
    name = I(c("Tukey", "Venables", "Tierney", "Ripley", "McNeil")),
    nationality = c("US", "Australia", "US", "UK", "Australia"),
    deceased = c("yes", rep("no", 4)))
books <- data.frame(
    name = I(c("Tukey", "Venables", "Tierney",
             "Ripley", "Ripley", "McNeil", "R Core")),
    title = c("Exploratory Data Analysis",
              "Modern Applied Statistics ...",
              "LISP-STAT",
              "Spatial Statistics", "Stochastic Simulation",
              "Interactive Data Analysis",
              "An Introduction to R"),
    other.author = c(NA, "Ripley", NA, NA, NA, NA,
                     "Venables & Smith"))
person IRTFM    schedule 02.02.2016
comment
Хотя это похоже на рискованное дело. - person Rich Scriven; 03.02.2016
comment
По общему признанию. В конце концов нам может понадобиться включить положения, которые сделают это похожим на саму функцию слияния. Я действительно думаю, что это в основном то, что Хэдли делает в dplyr. Также можно попробовать спроектировать его так, чтобы он принимал 2 списка с необязательными аргументами. Если бы не было аргументов, по умолчанию он мог бы использовать пересечение, что в любом случае делает слияние, верно? - person IRTFM; 03.02.2016
comment
спасибо 42-, это слияние было примером. Вообще говоря, мне просто интересно передать оператору более 2 аргументов. Есть ли что-то кроме объединения всех [Arg2 - Argn]? Может быть, каскадный оператор, такой как ggplot, является выбором, но есть ли другой способ еще больше абстрагировать код? - person Mahdi Jadaliha; 03.02.2016
comment
R имеет средство с тремя точками для этой задачи. - person IRTFM; 03.02.2016
comment
поэтому я сделал этот оператор с ...: ``%^%` ‹- function(...){return(list(...))}` это легко запустить с 2 Arg: 1 %^% 2, теперь как я запустите его с более чем 2 Arg, если я не использую синтаксис функции, такой как %^%(1,2,3) - person Mahdi Jadaliha; 03.02.2016
comment
Я пока не понимаю цели этих усилий. Пользовательские функции действительно принимают только 2 аргумента, но первый или второй аргумент может быть списком. (Как показано выше.) Определение в вашем комментарии имеет только один аргумент, и при попытке его использования вы обнаружите, что второй аргумент игнорируется. Я бы подумал, что это будет что-то вроде '%^%' <- function(x, ...){ args <- list(...); func(x, args)}возможно с match.args для правильной квалификации аргументов из списка функций. И я действительно не советую использовать %^%, так как большинство людей думают, что это будет матричная операция. - person IRTFM; 04.02.2016