我想在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个变量,而不是多行。还有其他选择吗?
答案 0 :(得分:30)
Struggling Through Problems Blog
上有一个很好的答案这是从那里进行的,只做了很小的修改。
使用以下三个功能 (另外一个允许不同大小的列表)
# 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
更长的左手侧
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"
答案 1 :(得分:28)
例如,创建一行数据帧(比如说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
答案 2 :(得分:17)
我整理了一个R包zeallot来解决这个问题。 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
有关更多示例和信息,可以查看包vignette。
答案 3 :(得分:13)
这是我的想法。可能语法非常简单:
`%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
虽然没有经过充分测试。
答案 4 :(得分:10)
有潜在危险(与使用assign
一样有风险)的选项是Vectorize
assign
:
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)
a b
0 4
> b
[1] 4
> a
[1] 0
或者我认为您可以使用mapply
使用envir
自己的函数手动对其进行矢量化,这可能会使用Vectorize
参数的合理默认值。例如,assign
将返回一个具有相同环境属性namespace:base
的函数,在本例中为envir = parent.env(environment(assignVec))
,或者您可以设置{{1}}。
答案 5 :(得分:8)
正如其他人所解释的那样,似乎没有任何内置的东西......但你可以按如下方式设计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
答案 6 :(得分:4)
如果您的唯一要求是只有一行代码,那么如何:
> a<-values[2]; b<-values[4]
答案 7 :(得分:4)
https://stat.ethz.ch/R-manual/R-devel/library/base/html/list2env.html:
list2env(
list(
a=1,
b=2:4,
c=rpois(10,10),
d=gl(3,4,LETTERS[9:11])
),
envir=.GlobalEnv
)
答案 8 :(得分:4)
最近遇到了类似的问题,我尝试使用purrr::walk2
purrr::walk2(letters,1:26,assign,envir =parent.frame())
答案 9 :(得分:3)
list2env(setNames(as.list(rep(2,5)), letters[1:5]), .GlobalEnv)
服务于我的目的,即在前五个字母中分配五个2。
答案 10 :(得分:1)
我担心你正在寻找的优雅解决方案(如c(a, b) = c(2, 4)
)不幸存在。 但是不要放弃,我不确定!我能想到的最近的解决方案就是这个:
attach(data.frame(a = 2, b = 4))
如果您对警告感到困扰,请将其关闭:
attach(data.frame(a = 2, b = 4), warn = F)
但我想你对这个解决方案不满意,我也不会......
答案 11 :(得分:1)
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
答案 12 :(得分:0)
另一个带递归的版本:
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]
答案 13 :(得分:0)
结合这里给出的一些答案和一些盐,该解决方案如何:
assignVec <- Vectorize("assign", c("x", "value"))
`%<<-%` <- function(x, value) invisible(assignVec(x, value, envir = .GlobalEnv))
c("a", "b") %<<-% c(2, 4)
a
## [1] 2
b
## [1] 4
我用它在此处添加R部分:http://rosettacode.org/wiki/Sort_three_variables#R
注意:仅适用于分配全局变量(如<<-
)。如果有更好,更通用的解决方案,请。在评论中告诉我。