R에서 참조로 전달할 수 있습니까?
"R"을 참조하여 전달할 수 있습니까? 예를 들어, 다음 코드에서 :
setClass("MyClass",
representation(
name="character"
))
instance1 <-new("MyClass",name="Hello1")
instance2 <-new("MyClass",name="Hello2")
array = c(instance1,instance2)
instance1
array
instance1@name="World!"
instance1
array
출력은
> instance1
An object of class “MyClass”
Slot "name":
[1] "World!"
> array
[[1]]
An object of class “MyClass”
Slot "name":
[1] "Hello1"
[[2]]
An object of class “MyClass”
Slot "name":
[1] "Hello2"
하지만 나는 그것이
> instance1
An object of class “MyClass”
Slot "name":
[1] "World!"
> array
[[1]]
An object of class “MyClass”
Slot "name":
[1] "World!"
[[2]]
An object of class “MyClass”
Slot "name":
[1] "Hello2"
가능합니까?
아니 .
할당 문의 개체는 변경할 수 없습니다. R은 참조 뿐만 아니라 객체를 복사합니다 .
> v = matrix(1:12, nrow=4)
> v
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> v1 = v
> v1[,1] # fetch the first column
[1] 1 2 3 4
( 단 , 위의 설명은 R 프리미티브 , 예를 들어 벡터, 행렬) 및 함수에 대해서도 참입니다 . 모든 R 객체에 대해 사실인지 확실하게 말할 수 없습니다. 대부분의 객체뿐 아니라 가장 자주 사용되는 객체의 대다수도 마찬가지입니다.)
이 동작이 마음에 들지 않으면 R 패키지의 도움을 받아 옵트 아웃 할 수 있습니다. 예를 들어, 참조에 의한 전달 동작을 모방 할 수있는 R.oo 라는 R 패키지 가 있습니다. R.oo는 CRAN에서 사용할 수 있습니다 .
수정되지 않은 객체 복사의 성능 영향을 피하기 위해 참조에 의한 전달을 사용하려는 경우 (상수 참조가있는 다른 언어에서 일반적으로 그렇듯이) R은이를 자동으로 수행합니다.
n <- 10^7
bigdf <- data.frame( x=runif(n), y=rnorm(n), z=rt(n,5) )
myfunc <- function(dat) invisible(with( dat, x^2+mean(y)+sqrt(exp(z)) ))
myfunc2 <- function(dat) {
x <- with( dat, x^2+mean(y)+sqrt(exp(z)) )
invisible(x)
}
myfunc3 <- function(dat) {
dat[1,1] <- 0
invisible( with( dat, x^2+mean(y)+sqrt(exp(z)) ) )
}
tracemem(bigdf)
> myfunc(bigdf)
> # nothing copied
> myfunc2(bigdf)
> # nothing copied!
> myfunc3(bigdf)
tracemem[0x6e430228 -> 0x6b75fca0]: myfunc3
tracemem[0x6b75fca0 -> 0x6e4306f0]: [<-.data.frame [<- myfunc3
tracemem[0x6e4306f0 -> 0x6e4304f8]: [<-.data.frame [<- myfunc3
>
> library(microbenchmark)
> microbenchmark(myfunc(bigdf), myfunc2(bigdf), myfunc3(bigdf), times=5)
Unit: milliseconds
expr min lq median uq max
1 myfunc2(bigdf) 617.8176 641.7673 644.3764 683.6099 698.1078
2 myfunc3(bigdf) 1052.1128 1134.0822 1196.2832 1202.5492 1206.5925
3 myfunc(bigdf) 598.9407 622.9457 627.9598 642.2727 654.8786
As several have pointed out before, this can be done via using objects of class environment
. There exists a formal approach building upon the use of environment
s. It's called Reference Classes and makes things really easy for you. Check ?setRefClass
for the main entry help page. It also describes how to use formal methods with Reference Classes.
Example
setRefClass("MyClass",
fields=list(
name="character"
)
)
instance1 <- new("MyClass",name="Hello1")
instance2 <- new("MyClass",name="Hello2")
array = c(instance1,instance2)
instance1$name <- "World!"
Output
> instance1
Reference class object of class "MyClass"
Field "name":
[1] "World!"
> array
[[1]]
Reference class object of class "MyClass"
Field "name":
[1] "World!"
[[2]]
Reference class object of class "MyClass"
Field "name":
[1] "Hello2"
Pass-by-reference is possible for environment
s. To use them, basically whenever you create an object you would need to create an environment slot as well. But I think that it is cumbersome. Have a look at Pass by reference for S4. and Pointers and passing by reference in R
R does have a library now that allows you to do OOP using references. See ReferenceClasses which is part of the methods package.
Actually the R.oo package emulates the pass-by-reference behaviour by using environments.
As other have stated, it's not possible for S4 classes. But R now provides the possibility with R6 library, called reference classes. See official documentation
In addition to the other answers here that actually pass your object by reference (environment
objects and Reference Classes), if you're purely interested in call-by-reference for syntactic convenience (i.e. you don't mind your data copied inside), you could emulate that by assigning the final value back to the outside variable while returning:
byRef <- function(..., envir=parent.frame(), inherits=TRUE) {
cl <- match.call(expand.dots = TRUE)
cl[c(1, match(c("envir", "inherits"), names(cl), 0L))] <- NULL
for (x in as.list(cl)) {
s <- substitute(x)
sx <- do.call(substitute, list(s), envir=envir)
dx <- deparse(sx)
expr <- substitute(assign(dx, s, envir=parent.frame(), inherits=inherits))
do.call(on.exit, list(expr, add=TRUE), envir=envir)
}
}
Then we can declare "call-by-reference" arguments:
f <- function(z1, z2, z3) {
byRef(z1, z3)
z1 <- z1 + 1
z2 <- z2 + 2
z3 <- z3 + 3
c(z1, z2, z3)
}
x1 <- 10
x2 <- 20
x3 <- 30
# Values inside:
print(f(x1, x2, x3))
# [1] 11 22 33
# Values outside:
print(c(x1, x2, x3))
# [1] 11 20 33
Note that if you access the "by-reference" variables by their outside names (x1
, x3
) anywhere inside the function, you'll get their yet-unmodified values from the outside. Also, this implementation only handles simple variable names as arguments, so indexed arguments such as f(x[1], ...)
will not work (though you could probably implement that with a bit more involved expression manipulation to sidestep the limited assign
).
On top of the other suggestions, you can also write C/C++ functions taking their arguments by reference and working in-place, and call them directly in R thanks to Rcpp
(among others). See in particular this answer.
참고URL : https://stackoverflow.com/questions/2603184/can-you-pass-by-reference-in-r
'Programing' 카테고리의 다른 글
SQL WHERE-Clause의 집계 함수 (0) | 2020.11.14 |
---|---|
.NET 4.5로 업그레이드 한 후 iFrame 파서 오류 (0) | 2020.11.14 |
: has_many : through 연관에 조인이있는 범위 (0) | 2020.11.14 |
android 내 자신의 활동을 만들고 확장하는 방법은 무엇입니까? (0) | 2020.11.14 |
직접 실행 창에서 동적으로 인해 'Microsoft.CSharp.RuntimeBinder.Binder'가 정의되지 않았거나 가져온 오류가 발생합니다. (0) | 2020.11.14 |