한 줄로 LHS에 여러 새 변수 할당


90

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 개의 변수를 할당하고 싶습니다. 대안이 있습니까?


PHP에서와 같은 것을 의미 list($a, $b) = array(1, 2)합니까? 그것은 좋을 것입니다! +1.
TMS

@Tomas T - 내 생각 vassign제안 아래 :) ... 가까이 온다
토미

참고 :이 R 비트에는 세미콜론이 필요하지 않습니다.
Iterator

1
적절한 환경에서이 작업을 시도한다면 X <- list();X[c('a','b')] <- values[c(2,4)]. 좋습니다. 작업 공간에 할당하지 않고 목록에 잘 정리해 둡니다. 나는 그렇게하는 것을 선호합니다.
Joris Meys 2013

7
나는 파이썬, 단지 a, b = 1,2를 좋아합니다. 모든 해답은 아래에 100 배 더 어렵다
appleLover

답변:


40

문제 해결 블로그 에 훌륭한 답변이 있습니다.

이것은 아주 사소한 수정으로 거기에서 가져옵니다.

다음 세 가지 기능 사용 (다른 크기의 목록을 허용하는 기능 추가)

# 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"

34

기본 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

5
내가 할 수 있다면 +10. 사람들이 그렇게 명백한 경우에 목록을 사용하는 것을 거부하는 이유가 무엇인지 궁금합니다. (데이터 프레임은 특별한 종류의 목록이므로 목록을 사용합니다. 더 일반적인 목록을 사용하겠습니다.)
Joris Meys

하지만 당신은 동일한 열 요소의 다른 종류를 할 수 없으며, 당신은 당신의 dataframe 내부 dataframes 또는 목록에 저장할 수 있습니다
SKAN

1
실제로 데이터 프레임에 목록을 저장할 수 있습니다-Google "목록 열".

그것은 나쁜 접근 방식이 아니며, 약간의 편리함이 있지만, 왜 많은 사용자가 이러한 방식으로 할당 된 변수를 사용하거나 액세스하려고 할 때마다 data.frame 구문을 처리하지 않으려는 이유를 상상하는 것도 어렵지 않습니다.
Brandon

34

저는 이 문제를 해결하기 위해 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

더 많은 예와 정보를 보려면 패키지 비 네트를 확인하십시오 .


이것이 바로 제가 찾고자했던 것입니다. OP가 요구하는 파이썬과 같은 구문을 가능하게하는 것, R 패키지로 구현되었습니다
jafelds

1
각 변수 이름에 행렬을 할당하는 것은 어떻습니까?
StatsSorceress

14

여기 내 생각이 있습니다. 아마도 구문은 매우 간단합니다.

`%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

이것은 잘 테스트되지 않았습니다.


3
Koshke, 나에게 아주 좋아 보인다 :-) 그러나 나는 연산자 우선 순위에 대해 약간 걱정하고있다 : % something % 연산자는 꽤 높기 때문에 c(c, d) %tin% c(1, 2) + 3(=> c = 1, d = 1의 동작은 숫자 ( 0)) 놀라운 것으로 간주 될 수 있습니다.
SX에 불만 cbeleites

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)).


9

다른 사람들이 설명했듯이 내장 된 것이없는 것 같습니다. ... 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

나는 이것을 좋아하지만 함수 내에서 호출되는 경우에 깨질 수 있다고 걱정할 것입니다 (간단한 테스트가 작동했지만 약간 놀랍습니다). 설명 ...()해주실 수 있나요? 흑 마법 같네요 ...?
Ben Bolker 2011 년

1
@Ben Bolker-예, ...()극단적 인 흑 마법입니다 ;-). 따라서 "함수 호출" ...()이 대체되면 전달 될 수있는 쌍 목록이 as.character되고 짜잔 한 인수를 문자열로 얻습니다 .
Tommy

1
@Ben Bolker-그리고 그것은 사용하기 때문에 함수 내에서 호출 된 경우에도 올바르게 작동해야합니다 envir=parent.frame().-그리고 envir=globalenv()원하는 경우 예를 지정할 수 있습니다 .
Tommy

더 멋진 것은 이것을 대체 기능 `vassign<-` <- function (..., envir = parent.frame (), value)으로 사용하는 것입니다. 그러나 할당 할 첫 번째 개체가 이미 존재해야하는 것 같습니다. 어떤 아이디어?
SX에 불만 cbeleites

@cbeleites-예, 더 멋지 겠지만 첫 번째 인수가 존재해야하는 한계를 해결할 수 없다고 생각합니다. 그래서 대체 함수라고합니다. !
Tommy

6
list2env(setNames(as.list(rep(2,5)), letters[1:5]), .GlobalEnv)

내 목적을 달성했습니다. 즉, 처음 5 개의 글자에 5 개의 2를 할당하는 것입니다.



5

최근에 비슷한 문제가 있었고 여기에 내 시도가있었습니다. purrr::walk2

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

3

단 한 줄의 코드 만 사용하는 것이 유일한 요구 사항이라면 다음을 수행하십시오.

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

2
간결 문을 찾고 있지만 추측했다 없음이
user236215는

저는 @ user236215와 같은 보트에 있습니다. 오른쪽은 벡터를 반환 복잡한 표현, 코드를 반복하는 것은 매우 잘못된 것입니다 때 ...
공습

1

나는 당신이 찾고있는 (예 :) 불편한 해결책이 c(a, b) = c(2, 4)존재하지 않는 것이 두렵습니다 . 하지만 포기하지 마세요. 잘 모르겠습니다! 내가 생각할 수있는 가장 가까운 해결책은 다음과 같습니다.

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

또는 경고가 신경 쓰이는 경우 끄십시오.

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

하지만이 솔루션에 만족하지 않는다고 생각합니다. 저도 마찬가지입니다.


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

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] 

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

주의 사항 : 전역 변수 (예 :)를 할당하는 경우에만 작동합니다 <<-. 더 나은, 더 일반적인 해결책이 있다면 pls. 댓글로 알려주세요.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.