Назначить несколько новых переменных на LHS в одной строке

Я хочу назначить несколько переменных в одной строке в R. Возможно ли сделать что-то подобное?

values # initialize some vector of values (a, b) = values[c(2,4)] # assign a and b to values at 2 and 4 indices of 'values' 

Обычно я хочу назначить около 5-6 переменных в одной строке вместо нескольких строк. Есть ли альтернатива?

Существует большой ответ на блог « Борьба через проблемы»

Это взято оттуда с очень незначительными изменениями.

ИСПОЛЬЗОВАНИЕ СЛЕДУЮЩИХ ТРЕХ ФУНКЦИЙ (плюс один для учета списков разных размеров)

 # Generic form '%=%' = function(l, r, ...) UseMethod('%=%') # Binary Operator '%=%.lbunch' = function(l, r, ...) { Envir = as.environment(-1) if (length(r) > length(l)) warning("RHS has more args than LHS. Only first", length(l), "used.") if (length(l) > length(r)) { warning("LHS has more args than RHS. RHS will be repeated.") r <- extendToMatch(r, l) } for (II in 1:length(l)) { do.call('<-', list(l[[II]], r[[II]]), envir=Envir) } } # Used if LHS is larger than RHS extendToMatch <- function(source, destin) { s <- length(source) d <- length(destin) # Assume that destin is a length when it is a single number and source is not if(d==1 && s>1 && !is.null(as.numeric(destin))) d <- destin dif <- d - s if (dif > 0) { source <- rep(source, ceiling(d/s))[1:d] } return (source) } # Grouping the left hand side g = function(...) { List = as.list(substitute(list(...)))[-1L] class(List) = 'lbunch' return(List) } 

Затем выполнить:

Группируйте левую сторону с помощью новой функции g() Правая сторона должна быть вектором или списком. Используйте созданный двоичный оператор %=%

 # Example Call; Note the use of g() AND `%=%` # Right-hand side can be a list or vector g(a, b, c) %=% list("hello", 123, list("apples, oranges")) g(d, e, f) %=% 101:103 # Results: > a [1] "hello" > b [1] 123 > c [[1]] [1] "apples, oranges" > d [1] 101 > e [1] 102 > f [1] 103 

Пример использования списков разных размеров:

Более длинная левая arm

 g(x, y, z) %=% list("first", "second") # Warning message: # In `%=%.lbunch`(g(x, y, z), list("first", "second")) : # LHS has more args than RHS. RHS will be repeated. > x [1] "first" > y [1] "second" > z [1] "first" 

Более длинная правая сторона

 g(j, k) %=% list("first", "second", "third") # Warning message: # In `%=%.lbunch`(g(j, k), list("first", "second", "third")) : # RHS has more args than LHS. Only first2used. > j [1] "first" > k [1] "second" 

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

Например, создайте 1-строчный фрейм (например, V ) и инициализируйте свои переменные в нем. Теперь вы можете назначить сразу нескольким переменным V[,c("a", "b")] <- values[c(2, 4)] , называть каждый по имени ( V$a ) или использовать многие из ( values[c(5, 6)] <- V[,c("a", "b")] ).

Если вы ленитесь и не хотите обойти вызовы переменных из фреймворка данных, вы можете attach(V) (хотя лично я этого не делаю).

 # Initialize values values <- 1:100 # V for variables V <- data.frame(a=NA, b=NA, c=NA, d=NA, e=NA) # Assign elements from a vector V[, c("a", "b", "e")] = values[c(2,4, 8)] # Also other class V[, "d"] <- "R" # Use your variables V$a V$b V$c # OOps, NA V$d V$e 

вот моя идея. Вероятно, синтаксис довольно прост:

 `%tin%` <- function(x, y) { mapply(assign, as.character(substitute(x)[-1]), y, MoreArgs = list(envir = parent.frame())) invisible() } c(a, b) %tin% c(1, 2) 

дает следующее:

 > a Error: object 'a' not found > b Error: object 'b' not found > c(a, b) %tin% c(1, 2) > a [1] 1 > b [1] 2 

это не очень хорошо протестировано.

Как объясняли другие, нет ничего встроенного … но вы могли бы vassign функцию vassign следующим образом:

 vassign <- function(..., values, envir=parent.frame()) { vars <- as.character(substitute(...())) values <- rep(values, length.out=length(vars)) for(i in seq_along(vars)) { assign(vars[[i]], values[[i]], envir) } } # Then test it vals <- 11:14 vassign(aa,bb,cc,dd, values=vals) cc # 13 

Одна вещь, которую следует учитывать, - это как обрабатывать случаи, когда вы, например, указываете 3 переменные и 5 значений или наоборот. Здесь я просто повторяю (или усекаю) значения, имеющие ту же длину, что и переменные. Возможно, предупреждение было бы разумным. Но это позволяет:

 vassign(aa,bb,cc,dd, values=0) cc # 0 

Потенциально опасным (так как использование assign является рискованным) вариантом будет assign Vectorize :

 assignVec <- Vectorize("assign",c("x","value")) #.GlobalEnv is probably not what one wants in general; see below. assignVec(c('a','b'),c(0,4),envir = .GlobalEnv) ab 0 4 > b [1] 4 > a [1] 0 

Или, я полагаю, вы могли бы его самостоятельно векторизовать с помощью своей собственной функции, используя mapply которая может использовать разумное значение по умолчанию для аргумента envir . Например, Vectorize вернет функцию с теми же свойствами среды assign , которая в этом случае является namespace:base , или вы можете просто установить envir = parent.env(environment(assignVec)) .

Я собрал рэллот R для решения этой самой проблемы. zeallot включает оператор ( %<-% ) для распаковки, множественного и деструктурирующего назначения. LHS выражения присваивания строится с использованием вызовов c() . RHS выражения присваивания может быть любым выражением, которое возвращает или является вектором, списком, вложенным списком, фреймом данных, символьной строкой, объектом даты или пользовательскими объектами (при условии, что существует реализация destructure ).

Вот начальный вопрос, переработанный с использованием zeallot (последняя версия, 0.0.5).

 library(zeallot) values <- c(1, 2, 3, 4) # initialize a vector of values c(a, b) %<-% values[c(2, 4)] # assign `a` and `b` a #[1] 2 b #[1] 4 

Для получения дополнительных примеров и информации можно проверить виньетку .

Если ваше единственное требование – иметь одну строку кода, то как насчет:

 > a<-values[2]; b<-values[4] 

https : /:

 list2env( list( a=1, b=2:4, c=rpois(10,10), d=gl(3,4,LETTERS[9:11]) ), envir=.GlobalEnv ) 

Недавно возникла аналогичная проблема, и здесь я попытался использовать purrr::walk2

 purrr::walk2(letters,1:26,assign,envir =parent.frame()) 

Боюсь, что элегантное решение, которое вы ищете (например, c(a, b) = c(2, 4) ), к сожалению, не существует. Но не сдавайся, я не уверен! Ближайшее решение, о котором я могу думать, это следующее:

 attach(data.frame(a = 2, b = 4)) 

или если вас беспокоят предупреждения, выключите их:

 attach(data.frame(a = 2, b = 4), warn = F) 

Но я полагаю, вы не удовлетворены этим решением, я бы тоже не был …

 R> values = c(1,2,3,4) R> a <- values[2]; b <- values[3]; c <- values[4] R> a [1] 2 R> b [1] 3 R> c [1] 4 

Другая версия с рекурсией:

 let <- function(..., env = parent.frame()) { f <- function(x, ..., i = 1) { if(is.null(substitute(...))){ if(length(x) == 1) x <- rep(x, i - 1); stopifnot(length(x) == i - 1) return(x); } val <- f(..., i = i + 1); assign(deparse(substitute(x)), val[[i]], env = env); return(val) } f(...) } 

пример:

 > let(a, b, 4:10) [1] 4 5 6 7 8 9 10 > a [1] 4 > b [1] 5 > let(c, d, e, f, c(4, 3, 2, 1)) [1] 4 3 2 1 > c [1] 4 > f [1] 1 

Моя версия:

 let <- function(x, value) { mapply( assign, as.character(substitute(x)[-1]), value, MoreArgs = list(envir = parent.frame())) invisible() } 

пример:

 > let(c(x, y), 1:2 + 3) > x [1] 4 > y [1] 
 list2env(setNames(as.list(rep(2,5)), letters[1:5]), .GlobalEnv) 

Служил моей цели, т. Е. Назначил пять секунд на первые пять букв.

Давайте будем гением компьютера.