複数の値を返す関数から割り当てる方法は?


223

まだRロジックに取り込もうとしています...複数の値を返す関数からの結果を(LHSで)アンパックする「最良の」方法は何ですか?

どうやらこれはできません:

R> functionReturningTwoValues <- function() { return(c(1, 2)) }
R> functionReturningTwoValues()
[1] 1 2
R> a, b <- functionReturningTwoValues()
Error: unexpected ',' in "a,"
R> c(a, b) <- functionReturningTwoValues()
Error in c(a, b) <- functionReturningTwoValues() : object 'a' not found

私は本当に次のことをしなければなりませんか?

R> r <- functionReturningTwoValues()
R> a <- r[1]; b <- r[2]

または、Rプログラマーは次のように記述します。

R> functionReturningTwoValues <- function() {return(list(first=1, second=2))}
R> r <- functionReturningTwoValues()
R> r$first
[1] 1
R> r$second
[1] 2

---シェーンの質問に答えるために編集---

結果の値の部分に名前を付ける必要は本当にありません。私は、第二成分を第一成分と他の1つの集計関数を適用(AM minmax。それは私が分割それらを必要としない両方の成分に対して同じ関数であった場合)。


7
attr参考までに、複数の値を返す別の方法は、戻り値にを設定することです。
ジョナサン・チャン

これはPythonのタプルアンパックと同等です。
smci 2015年

回答:


186

(1)list [...] <- 10年以上前にr-helpに投稿しました。それ以来、それはgsubfnパッケージに追加されました。特別な演算子は必要ありませんが、左側を次のlist[...]ように記述する必要があります。

library(gsubfn)  # need 0.7-0 or later
list[a, b] <- functionReturningTwoValues()

最初または2番目のコンポーネントのみが必要な場合、これらすべても機能します。

list[a] <- functionReturningTwoValues()
list[a, ] <- functionReturningTwoValues()
list[, b] <- functionReturningTwoValues()

(もちろん、あなたがだけにして一つの値を必要に応じて、functionReturningTwoValues()[[1]]またはfunctionReturningTwoValues()[[2]]十分であろう。)

その他の例については、引用されているr-helpスレッドを参照してください。

(2)with 意図が単に複数の値を組み合わせることであり、戻り値に名前が付けられている場合、単純な代替策は以下を使用することwithです:

myfun <- function() list(a = 1, b = 2)

list[a, b] <- myfun()
a + b

# same
with(myfun(), a + b)

(3)アタッチ別の選択肢はアタッチです:

attach(myfun())
a + b

追加:withおよびattach


25
「with」のせいであなたの答えを受け入れましたが、「list」の左側の使用法についてあなたが説明したことを再現できません。私が得るのは「object 'a' not found」だけです
mariotomo

4
わたしにはできる。何を試しましたか?リンクされた投稿を読んでフォローしましたか?そこに示されているように定義list[<-.resultましたか?
G.グロタンディーク2013年

12
@ G.Grothendieck、あなたのリンクの内容をあなたの答えに入れてもよろしいですか?利用しやすくなると思います。
merlin2011 2014

12
@ merlin2011に同意します。書かれているように、この構文はRベースに埋め込まれているようです。
ノワ

6
@ G.Grothendieck私はmerlin2011とKnowahに同意します-ここで重要な実際のコード(リンクで参照されているコード)が答えに含まれているのが最善です。結果オブジェクトは名前付きリストである必要がないことを述べることは悪い考えではないかもしれません。実際のコードを読む前に、少し混乱しました。答えを述べたあなたは、リンクでコードを実行する必要があるが、それは直接の回答でありますしない限り、ほとんどの人はすぐにそのコードを読んでするつもりはないと言っている-これは、この構文はベースR.であるという印象を与えます
Dason

68

どういうわけか、インターネットでこの巧妙なハックに遭遇しました...それが厄介なものか美しいものかはわかりませんが、複数の戻り値を独自の変数にアンパックできる「魔法の」演算子を作成できます。:=関数は、ここで定義され、そして後世のために以下に含ま:

':=' <- function(lhs, rhs) {
  frame <- parent.frame()
  lhs <- as.list(substitute(lhs))
  if (length(lhs) > 1)
    lhs <- lhs[-1]
  if (length(lhs) == 1) {
    do.call(`=`, list(lhs[[1]], rhs), envir=frame)
    return(invisible(NULL)) 
  }
  if (is.function(rhs) || is(rhs, 'formula'))
    rhs <- list(rhs)
  if (length(lhs) > length(rhs))
    rhs <- c(rhs, rep(list(NULL), length(lhs) - length(rhs)))
  for (i in 1:length(lhs))
    do.call(`=`, list(lhs[[i]], rhs[[i]]), envir=frame)
  return(invisible(NULL)) 
}

それを手に入れれば、自分がやりたいことができるようになります。

functionReturningTwoValues <- function() {
  return(list(1, matrix(0, 2, 2)))
}
c(a, b) := functionReturningTwoValues()
a
#[1] 1
b
#     [,1] [,2]
# [1,]    0    0
# [2,]    0    0

私はそれについてどう感じているのかわかりません。おそらく、インタラクティブなワークスペースで役立つかもしれません。(大量)の(再)使用可能なライブラリを構築するためにそれを使用することは最良のアイデアではないかもしれませんが、それはあなた次第だと思います。

...あなたは彼らが責任と権力について言うことを知っています...


12
また、data.tableパッケージは:=演算子muchoを非常に
便利

47

通常、出力をリストにラップします。これは非常に柔軟です(数値、文字列、ベクトル、行列、配列、リスト、出力内のオブジェクトの任意の組み合わせを使用できます)。

以下のようなので:

func2<-function(input) {
   a<-input+1
   b<-input+2
   output<-list(a,b)
   return(output)
}

output<-func2(5)

for (i in output) {
   print(i)
}

[1] 6
[1] 7

output <-func2(5)の代わりに2つのオブジェクトで結果を取得したい場合はどうなりますか?list( "a"、 "b")<-func2(5)を試してみましたが、機能しません。
skan 2017

13
functionReturningTwoValues <- function() { 
  results <- list()
  results$first <- 1
  results$second <-2
  return(results) 
}
a <- functionReturningTwoValues()

これはうまくいくと思います。


11

私はこの問題に取り組むためにRパッケージの熱意をまとめました。zeallotには、複数の代入演算子またはアンパック代入演算子が含まれています%<-%。演算子のLHSは、割り当てる任意の数の変数であり、への呼び出しを使用して構築されますc()。演算子のRHSは、ベクトル、リスト、データフレーム、日付オブジェクト、または実装されたdestructureメソッドを持つカスタムオブジェクト?zeallot::destructureです(を参照)。

以下は、元の投稿に基づいたいくつかの例です。

library(zeallot)

functionReturningTwoValues <- function() { 
  return(c(1, 2)) 
}

c(a, b) %<-% functionReturningTwoValues()
a  # 1
b  # 2

functionReturningListOfValues <- function() {
  return(list(1, 2, 3))
}

c(d, e, f) %<-% functionReturningListOfValues()
d  # 1
e  # 2
f  # 3

functionReturningNestedList <- function() {
  return(list(1, list(2, 3)))
}

c(f, c(g, h)) %<-% functionReturningNestedList()
f  # 1
g  # 2
h  # 3

functionReturningTooManyValues <- function() {
  return(as.list(1:20))
}

c(i, j, ...rest) %<-% functionReturningTooManyValues()
i     # 1
j     # 2
rest  # list(3, 4, 5, ..)

詳細と例については、パッケージビネットを確認してください。


この方法を使用して複数のプロットを出力として保存するための特別な構文はありますか?
mrpargeter 2018年

2
特別な構文は必要ありません。数値のリストと同じように、プロットオブジェクトのリストを割り当てることができます。
nteetor 2018年

10

この質問に対する正しい答えはありません。私は本当にあなたがデータで何をしているかに依存します。上記の簡単な例では、私は強くお勧めします:

  1. 物事はできるだけシンプルにしてください。
  2. 可能な限り、関数をベクトル化しておくことをお勧めします。これにより、長期的には最大の柔軟性と速度が実現します。

上記の値1と2に名前があることは重要ですか?つまり、この例で、r [1]とr [2]だけでなく、1と2にaとbを付けることが重要なのはなぜですか。この文脈で理解しておくべき重要なことの1つは、aとbはどちら長さ1のベクトルであることです。したがって、その割り当てを行う過程で、添え字を必要としない2つの新しいベクトル以外は何も変更しません。参照される:

> r <- c(1,2)
> a <- r[1]
> b <- r[2]
> class(r)
[1] "numeric"
> class(a)
[1] "numeric"
> a
[1] 1
> a[1]
[1] 1

インデックスではなく文字を参照する場合は、元のベクトルに名前を割り当てることもできます。

> names(r) <- c("a","b")
> names(r)
[1] "a" "b"
> r["a"]
a 
1 

[編集]各ベクトルに個別に最小値と最大値を適用する場合、マトリックス(aとbが同じ長さで同じデータ型の場合)またはデータフレーム(aとbが同じ場合)を使用することをお勧めします長さは同じですが、データ型が異なる場合があります)、または最後の例のようにリストを使用します(長さとデータ型が異なる場合があります)。

> r <- data.frame(a=1:4, b=5:8)
> r
  a b
1 1 5
2 2 6
3 3 7
4 4 8
> min(r$a)
[1] 1
> max(r$b)
[1] 8

コメントを含めるために質問を編集しました。ありがとう。のようなものに名前を付けるr[1]ことは、物事をより明確にするのに役立ちます(aそのような名前がその場所に来たとしても大丈夫です)
mariotomo 09

5

リストはこの目的に最適です。たとえば、関数内で

x = desired_return_value_1 # (vector, matrix, etc)

y = desired_return_value_2 # (vector, matrix, etc)

returnlist = list(x,y...)

}  # end of function

メインプログラム

x = returnlist[[1]]

y = returnlist[[2]]

4
list( "x"、 "y")<-returnlist()のように、両方の変数を1つのコマンドでどのように割り当てることができますか?リストに多くの要素がある場合、関数全体を数回実行する必要があり、それには時間がかかるためです。
skan 2017


3

割り当てを使用するのはどうですか?

functionReturningTwoValues <- function(a, b) {
  assign(a, 1, pos=1)
  assign(b, 2, pos=1)
}

参照渡ししたい変数の名前を渡すことができます。

> functionReturningTwoValues('a', 'b')
> a
[1] 1
> b
[1] 2

既存の値にアクセスする必要がある場合は、の逆になりassignますget


...しかし、これには、その環境で受け取る変数の名前を知っている必要があります
smci

@smciはい。これが、質問の「名前付きリスト」メソッドの方が一般的に優れている理由です。そして、およびr <- function() { return(list(first=1, second=2)) }を使用r$firstして結果を参照しますr$second
Steve Pitchers 2015年

2
関数を取得したら、list( "x"、 "y")のように、両方の変数を1つのコマンドでどのように割り当てることができますか?<-functionReturningTwoValues( 'a'、 'b')?リストに多くの要素がある場合、関数全体を数回実行する必要があり、それには時間がかかるため
です

3

関数の出力をグローバル環境に戻したい場合はlist2env、次の例のようにを使用できます。

myfun <- function(x) { a <- 1:x
                       b <- 5:x
                       df <- data.frame(a=a, b=b)

                       newList <- list("my_obj1" = a, "my_obj2" = b, "myDF"=df)
                       list2env(newList ,.GlobalEnv)
                       }
    myfun(3)

この関数は、グローバル環境に3つのオブジェクトを作成します。

> my_obj1
  [1] 1 2 3

> my_obj2
  [1] 5 4 3

> myDF
    a b
  1 1 5
  2 2 4
  3 3 3

1

[A] fooとbarがそれぞれ1つの数値である場合、c(foo、bar)には何の問題もありません。コンポーネントに名前を付けることもできます:c(Foo = foo、Bar = bar)。したがって、res '1'、res [2]として結果 'res'のコンポーネントにアクセスできます。または、名前付きの場合、res ["Foo"]、res ["BAR"]のようになります。

[B] fooとbarが同じタイプと長さのベクトルである場合、cbind(foo、bar)またはrbind(foo、bar)を返すことに何の問題もありません。同様に命名可能。'cbind'の場合、fooとbarにはres [、1]、res [、2]またはres [、 "Foo"]、res [、 "Bar"]としてアクセスします。また、マトリックスではなくデータフレームを返すこともできます。

data.frame(Foo=foo,Bar=bar)

res $ Foo、res $ Barとしてアクセスします。これは、fooとbarが同じ長さで同じタイプではない場合にもうまく機能します(たとえば、fooは数値のベクトル、barは文字列のベクトルです)。

[C] fooとbarが上記のようにうまく結合しないほど十分に異なる場合、リストを確実に返す必要があります。

たとえば、関数が線形モデルに適合し、予測値も計算する場合があるので、

LM<-lm(....) ; foo<-summary(LM); bar<-LM$fit

その後、あなたは希望return list(Foo=foo,Bar=bar)して、解像度$ Fooの、RES $バーとして予測値として要約にアクセス

ソース:http : //r.789695.n4.nabble.com/How-to-return-multiple-values-in-a-function-td858528.html


-1

関数から複数の出力を取得し、それらを目的の形式で保持するには、関数内から出力をハードディスク(作業ディレクトリ内)に保存し、関数の外部からロードします。

myfun <- function(x) {
                      df1 <- ...
                      df2 <- ...
                      save(df1, file = "myfile1")
                      save(df2, file = "myfile2")
}
load("myfile1")
load("myfile2")

-1

R 3.6.1では、次のことができます

fr2v <- function() { c(5,3) }
a_b <- fr2v()
(a_b[[1]]) # prints "5"
(a_b[[2]]) # prints "3"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.