在LHS中为一行分配多个新变量

use*_*215 79 variables tuples r variable-assignment assign

我想在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'
Run Code Online (Sandbox Code Playgroud)

通常我想在一行中分配大约5-6个变量,而不是多行.还有其他选择吗?

Ric*_*rta 31

苦苦挣扎的问题博客上有一个很好的答案

这是从那里采取的,只有很小的修改.

使用以下三个功能(加上一个允许不同大小的列表)

# 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)
}
Run Code Online (Sandbox Code Playgroud)


然后执行:

使用新函数对左侧进行分组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
Run Code Online (Sandbox Code Playgroud)


使用不同大小的列表的示例:

左手边更长

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"
Run Code Online (Sandbox Code Playgroud)

更长的右手边

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"
Run Code Online (Sandbox Code Playgroud)


小智 29

考虑使用基础R中包含的功能.

例如,创建一行数据帧(比如说V)并在其中初始化变量.现在,您可以一次分配多个变量,V[,c("a", "b")] <- values[c(2, 4)]通过name(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
Run Code Online (Sandbox Code Playgroud)

  • +10,如果可以的话.我想知道为什么人们拒绝在如此明显的情况下使用列表,而是在工作区中乱扔大量无意义的变量.(你确实使用列表,因为data.frame是一种特殊的列表.我只是使用更通用的列表.) (3认同)

nte*_*tor 26

我整理了一个R包zeallot来解决这个问题.zeallot包含一个operator(%<-%),用于解包,多重和解构赋值.赋值表达式的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
Run Code Online (Sandbox Code Playgroud)

有关更多示例和信息,可以查看包装插图.

  • 这正是我希望找到的,它可以实现OP所要求的类似python的语法,并在R包中实现 (3认同)

koh*_*ske 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)
Run Code Online (Sandbox Code Playgroud)

给出这样的:

> 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
Run Code Online (Sandbox Code Playgroud)

虽然这还没有经过充分测试.

  • Koshke,对我来说很好:-)但是我有点担心运算符的优先级:%something%运算符的位置很高,因此,例如`c(c,d)%tin%c(1, 2)+ 3`(=&gt; c = 1,d = 1,返回数值(0))可能令人惊讶。 (2认同)

jor*_*ran 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
Run Code Online (Sandbox Code Playgroud)

或者我想你可以使用你自己的函数自己手动矢量化它mapply可能使用一个合理的默认envir参数.例如,Vectorize将返回一个具有相同环境属性的函数assign,在这种情况下namespace:base,或者您可以设置envir = parent.env(environment(assignVec)).


Tom*_*mmy 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
Run Code Online (Sandbox Code Playgroud)

但要考虑的一件事是如何处理例如指定3个变量和5个值的情况,或者相反.在这里,我只需重复(或截断)与变量长度相同的值.也许警告是谨慎的.但它允许以下内容:

vassign(aa,bb,cc,dd, values=0)
cc # 0
Run Code Online (Sandbox Code Playgroud)


小智 6

list2env(setNames(as.list(rep(2,5)), letters[1:5]), .GlobalEnv)
Run Code Online (Sandbox Code Playgroud)

达到我的目的,即在前五个字母中分配五个2。


iso*_*mes 5

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
        )
Run Code Online (Sandbox Code Playgroud)


小智 5

最近有一个类似的问题,这是我尝试使用 purrr::walk2

purrr::walk2(letters,1:26,assign,envir =parent.frame()) 
Run Code Online (Sandbox Code Playgroud)


NPE*_*NPE 3

如果您唯一的要求是一行代码,那么:

> a<-values[2]; b<-values[4]
Run Code Online (Sandbox Code Playgroud)

  • 正在寻找一个简洁的声明,但我想没有 (2认同)
  • 我和@user236215在同一条船上。当右侧是返回向量的复杂表达式时,重复代码似乎非常错误...... (2认同)