web-dev-qa-db-ja.com

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"

出来ますか ?

60
Pierre

いいえ

割り当てステートメント内のオブジェクトは不変です。 Rは参照ではなくjustオブジェクトをコピーします。

> 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

proviso:上記の記述は、Rprimitives、たとえばベクトル、行列)、およびfunctions; allRオブジェクトに当てはまるかどうかは確かに言えません。ほとんどのオブジェクトと、最も頻繁に使用されるオブジェクトの大部分です。)

この動作が気に入らない場合は、Rパッケージの助けを借りてオプトアウトできます。たとえば、R.ooと呼ばれるRパッケージがあり、参照渡しの動作を模倣できます。 R.ooは [〜#〜] cran [〜#〜] で利用できます。

53
doug

変更されていないオブジェクトをコピーすることによるパフォーマンスへの影響を回避するためだけに参照渡しを使用したい場合(他の言語では定数参照が一般的です)、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
38
Ari B. Friedman

前にいくつか指摘したように、これはクラスenvironmentのオブジェクトを使用して行うことができます。 environmentsの使用に基づいた正式なアプローチがあります。 参照クラスと呼ばれ、非常に簡単になります。小切手 ?setRefClassメインエントリのヘルプページ。また、参照クラスで正式なメソッドを使用する方法についても説明します。

setRefClass("MyClass",
    fields=list(
        name="character"
    )
)

instance1 <- new("MyClass",name="Hello1")
instance2 <- new("MyClass",name="Hello2")

array = c(instance1,instance2)

instance1$name <- "World!"

出力

> 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"
19
Rappster

environmentsでは参照渡しが可能です。これらを使用するには、基本的にオブジェクトを作成するたびに、環境スロットも作成する必要があります。しかし、面倒だと思います。 S4の参照渡しRの参照と参照渡し をご覧ください

16
teucer

Rには、参照を使用してOOPを実行できるライブラリがあります。メソッドパッケージの一部である ReferenceClasses を参照してください。

5
Kyle Brandt

実際、R.ooパッケージは、環境を使用して参照渡し動作をエミュレートします。

4
user350780

他の人が述べたように、S4クラスでは不可能です。しかし、RはR6ライブラリ(referenceクラスと呼ばれる)の可能性を提供します。 公式ドキュメント を参照してください

3
Jules Randolph

ここで実際にpass参照によるオブジェクト(environmentオブジェクトと参照クラス)である他の回答に加えて、構文上の利便性のために参照による呼び出しに純粋に興味がある場合(つまり内部にコピーされたデータを気にしないでください)、返すときに外部変数に最終値を割り当てることでエミュレートできます:

_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)
  }
}
_

次に、「参照による呼び出し」引数を宣言できます。

_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
_

関数内の任意の場所で外部名(_x1_、_x3_)で「参照」変数にアクセスすると、まだ変更されていない値が外部から取得されることに注意してください。また、この実装は引数として単純な変数名のみを処理するため、f(x[1], ...)などのインデックス付き引数は機能しません(ただし、制限されたassignを回避するためにもう少し複雑な式操作を実装できます) )。

2
codeola

他の提案に加えて、参照および作業によって引数を取るC/C++関数を記述しin-place、Rで直接呼び出すこともできます(とりわけ)Rcppに感謝します。特に this answer を参照してください。

1
Hugo Raguet