एक फ़ंक्शन से कैसे असाइन किया जाए जो एक से अधिक मूल्य देता है?


223

फिर भी आर लॉजिक में जाने की कोशिश कर रहा है ... कई मूल्यों को लौटाने वाले फ़ंक्शन से परिणाम (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> functionReturningTwoValues <- function() {return(list(first=1, second=2))}
R> r <- functionReturningTwoValues()
R> r$first
[1] 1
R> r$second
[1] 2

--- शेन के सवालों का जवाब देने के लिए संपादित ---

मुझे वास्तव में परिणाम मूल्य भागों को नाम देने की आवश्यकता नहीं है। मैं पहले घटक और दूसरे को दूसरे घटक के लिए एक समग्र फ़ंक्शन लागू कर रहा हूं ( minऔर maxयदि यह दोनों घटकों के लिए एक ही फ़ंक्शन है तो मुझे उन्हें विभाजित करने की आवश्यकता नहीं होगी)।


7
FYI करें, कई मानों को वापस करने का एक अन्य तरीका यह है कि आप attrअपने रिटर्न वैल्यू को सेट करें।
जोनाथन चांग

यह पायथन के ट्यूपल-अनपैकिंग के बराबर है।
स्मिकी

जवाबों:


186

(1) सूची [...] <- मैंने इसे एक दशक पहले आर-हेल्प पर पोस्ट किया था । तब से इसे gsubfn पैकेज में जोड़ा गया है। इसके लिए एक विशेष ऑपरेटर की आवश्यकता नहीं होती है, लेकिन यह आवश्यक है कि बाएं हाथ की तरफ list[...]इस तरह से लिखा जाए :

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

यदि आपको केवल पहले या दूसरे घटक की जरूरत है तो ये सभी काम भी होंगे:

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

(बेशक, अगर आपको केवल एक मूल्य की आवश्यकता है functionReturningTwoValues()[[1]]या functionReturningTwoValues()[[2]]पर्याप्त होगा।)

अधिक उदाहरणों के लिए उद्धृत आर-हेल्प थ्रेड देखें।

(2) यदि इरादे बाद में कई मूल्यों को संयोजित करने के लिए है और रिटर्न मान नाम दिए गए हैं तो उपयोग करने के लिए एक सरल विकल्प है 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
मैंने "उत्तर" के कारण आपका उत्तर स्वीकार कर लिया है, लेकिन आप "सूची" के बाएं हाथ के उपयोग के लिए आपके द्वारा वर्णित वर्णन को पुन: प्रस्तुत नहीं कर सकते, मुझे जो भी मिलता है वह है "ऑब्जेक्ट 'ए' नहीं मिला"
मारीओतोमो

4
इससे मेरा काम बनता है। आपने क्या प्रयास किया? क्या आपने लिंक्ड पोस्ट पढ़ी और उसका पालन किया? क्या आपने परिभाषित किया listऔर [<-.resultजैसा कि वहां दिखाया गया है?
जी। ग्रोथेंडिक

12
अगर आप अपने लिंक की सामग्री आपके उत्तर में डालते हैं, तो क्या आपका नाम जीग्रोथेंडीक होगा? मुझे लगता है कि इससे लोगों के लिए इसका इस्तेमाल करना आसान हो जाएगा।
मर्लिन2011

12
मैं @ merlin2011 से सहमत हूं; जैसा कि लिखा गया है कि ऐसा लगता है कि यह सिंटैक्स आर बेस में एम्बेडेड है।
पताह

6
@ G.Grothendieck मैं merlin2011 और knowah से सहमत हूं - यह सबसे अच्छा होगा यदि वास्तविक कोड जो यहां महत्वपूर्ण है (लिंक में संदर्भित कोड) उत्तर में है। यह उल्लेख करने के लिए एक बुरा विचार नहीं हो सकता है कि परिणाम ऑब्जेक्ट को सूची का नाम देने की आवश्यकता नहीं है। आपके वास्तविक कोड को पढ़ने से पहले मुझे थोड़ी देर के लिए भ्रमित किया। जवाब में उल्लेख किया है कहते हैं आप लिंक में कोड चलाने की आवश्यकता लेकिन अधिकांश लोगों को जब तक यह जवाब सीधे में सही दूर है कि कोड को पढ़ने के लिए नहीं जा रहे हैं कि - यह धारणा है कि इस वाक्य आधार आर में है देता है
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
इसके अलावा, मैं इसे तब और अधिक हतोत्साहित करता हूं जब मैंने मूल रूप से इस उत्तर को पोस्ट किया था क्योंकि डेटाटेबल पैकेज बहुत अधिक हैंडियर तरीके से :=ऑपरेटर लॉटो का उपयोग करता है :-)
स्टीव लियानोग्लू

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

क्या होगा अगर आउटपुट के बजाय <-func2 (5) मैं दो वस्तुओं में परिणाम चाहता हूं? मैंने सूची ("ए", "बी") <-func2 (5) के साथ कोशिश की है, लेकिन यह काम नहीं करता है।
स्कंध

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

मुझे लगता है कि यह काम करता है।


11

मैंने इस समस्या से निपटने के लिए R पैकेज zeallot को एक साथ रखा । zeallot एक बहु काम या unpacking असाइनमेंट ऑपरेटर भी शामिल है, %<-%। ऑपरेटर का एलएचएस किसी भी प्रकार के चर को असाइन करने के लिए है, जिसे कॉल का उपयोग करके बनाया गया है c()। ऑपरेटर का आरएचएस एक सदिश, सूची, डेटा फ्रेम, दिनांक ऑब्जेक्ट, या किसी कस्टम ऑब्जेक्ट के साथ एक कार्यान्वित 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, ..)

अधिक जानकारी और उदाहरणों के लिए पैकेज विगनेट देखें।


क्या इस पद्धति का उपयोग करके आउटपुट के रूप में कई भूखंडों को संग्रहीत करने के लिए एक विशेष वाक्यविन्यास है?
अपराह्न

2
कोई विशेष वाक्यविन्यास की आवश्यकता नहीं है, आप संख्या की सूची के रूप में भूखंड की वस्तुओं की एक सूची प्रदान कर सकते हैं।
22

10

इस सवाल का कोई सही जवाब नहीं है। मैं वास्तव में इस बात पर निर्भर करता हूं कि आप डेटा के साथ क्या कर रहे हैं। उपरोक्त सरल उदाहरण में, मैं दृढ़ता से सुझाव दूंगा:

  1. चीजों को यथासंभव सरल रखें।
  2. जहाँ भी संभव हो, यह आपके कार्यों को सदिश रखने के लिए एक सर्वोत्तम अभ्यास है। यह लंबे समय में सबसे बड़ी मात्रा में लचीलापन और गति प्रदान करता है।

क्या यह महत्वपूर्ण है कि उपरोक्त 1 और 2 के नाम हैं? दूसरे शब्दों में, इस उदाहरण में यह महत्वपूर्ण क्यों है कि 1 और 2 को केवल r [1] और r [2] के बजाय a और b नाम दिया जाए? इस संदर्भ में समझने वाली एक महत्वपूर्ण बात यह है कि 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 

[संपादित करें] यह देखते हुए कि आप प्रत्येक वेक्टर पर न्यूनतम रूप से न्यूनतम और अधिकतम आवेदन करेंगे, मैं या तो एक मैट्रिक्स का उपयोग करने का सुझाव दूंगा (यदि ए और बी एक ही लंबाई और समान डेटा प्रकार होगा) या डेटा फ्रेम (यदि ए और बी होगा) समान लंबाई लेकिन अलग-अलग डेटा प्रकार हो सकते हैं) या अपने अंतिम उदाहरण में एक सूची का उपयोग करें (यदि वे अलग-अलग लंबाई और डेटा प्रकार के हो सकते हैं)।

> 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उनकी जगह पर जैसे नाम आते हैं)।
मारीतोमो

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
आप एक सूची में ("x", "y") <-पूर्णा सूची () जैसी एकल कॉमांड में दोनों चर कैसे दे सकते हैं? मैं ऐसा इसलिए कहता हूं क्योंकि यदि आप सूची में कई तत्व हैं तो आपको कई बार पूरे फ़ंक्शन को चलाने की आवश्यकता होगी और इसमें एक समय लगता है।
Skan

4

आपके दूसरे और तीसरे प्रश्न के लिए हाँ - यह वही है जो आपको करने की आवश्यकता है क्योंकि आपके पास एक असाइनमेंट के बाईं ओर कई 'lvalues' नहीं हो सकते हैं।


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

@ हसी हाँ। यही कारण है कि प्रश्न में "नामित सूची" विधि आम तौर पर बेहतर है: r <- function() { return(list(first=1, second=2)) }और उपयोग करने वाले परिणामों का संदर्भ लें r$firstऔर r$second
स्टीव पिचर्स

2
एक बार जब आप अपना कार्य कर लेते हैं, तो आप एक सूची में ("x", "y") <- functionReturningTwoValues ​​('a', 'b') जैसे एक ही कॉमांड में दोनों चर कैसे दे सकते हैं? मैं कहता हूं कि क्योंकि यदि आपके पास सूची में कई तत्व हैं तो आपको पूरे फ़ंक्शन को कई बार चलाने की आवश्यकता होगी और एक समय खर्च होता है
skan

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)

यह फ़ंक्शन आपके वैश्विक वातावरण में तीन ऑब्जेक्ट बनाएगा:

> 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

[ए] यदि प्रत्येक फू और बार एक एकल संख्या है, तो सी (फू, बार) के साथ कुछ भी गलत नहीं है; और आप घटकों को भी नाम दे सकते हैं: सी (फू = फू, बार = बार)। इसलिए आप परिणाम के घटकों को रेस [1], रेस [2] के रूप में एक्सेस कर सकते हैं; या, नामित मामले में, Res ["Foo"] के रूप में, res ["BAR"]।

[ख] अगर फू और बार एक ही प्रकार और लंबाई के वैक्टर हैं, तो फिर से cbind (फू, बार) या rbind (फू, बार) को लौटाने में कुछ भी गलत नहीं है; इसी तरह नाममात्र। 'Cbind' केस में, आप f और bar को Res [, 1], res [, 2] या res [, "Foo"], res [, "Bar"] के रूप में एक्सेस करेंगे। आप मैट्रिक्स के बजाय डेटाफ़्रेम वापस करना पसंद कर सकते हैं:

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

और उन्हें $ फू, रेस $ बार के रूप में एक्सेस करें। यह भी अच्छी तरह से काम करेगा अगर फू और बार एक ही लंबाई के थे, लेकिन एक ही प्रकार के नहीं थे (जैसे कि फू संख्या का वेक्टर है, वर्ण स्ट्रिंग का एक वेक्टर बार)।

[ग] यदि उपर्युक्त के अनुसार आसानी से गठबंधन नहीं करने के लिए फू और बार पर्याप्त रूप से भिन्न हैं, तो आप निश्चित रूप से एक सूची वापस कर देंगे।

उदाहरण के लिए, आपका फ़ंक्शन एक रेखीय मॉडल फिट हो सकता है और पूर्वानुमानित मूल्यों की गणना भी कर सकता है, इसलिए आप कर सकते हैं

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

और फिर आप return list(Foo=foo,Bar=bar)$ फू के रूप में सारांश का उपयोग करेंगे, $ $ के रूप में अनुमानित मूल्यों

स्रोत: 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"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.