سؤال

ما زلت تحاول الدخول في منطق 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

--- تم التعديل للإجابة على أسئلة شين ---

لا أحتاج حقًا إلى إعطاء أسماء لأجزاء القيمة الناتجة.أقوم بتطبيق دالة مجمعة واحدة على المكون الأول وأخرى على المكون الثاني (min و max.إذا كانت نفس الوظيفة لكلا المكونين فلن أحتاج إلى تقسيمهما).

هل كانت مفيدة؟

المحلول

(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]] سيكون كافيا.)

راجع موضوع المساعدة r المستشهد به لمزيد من الأمثلة.

(2) مع إذا كان القصد هو مجرد دمج القيم المتعددة لاحقًا وتم تسمية القيم المرجعة، فسيتم استخدام بديل بسيط with :

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

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

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

(٣) ألحق بديل آخر هو إرفاق:

attach(myfun())
a + b

تمت الإضافة: with و attach

نصائح أخرى

وأنا تعثرت بطريقة أو بأخرى على هذا الإختراق ذكي على شبكة الانترنت ... أنا لست متأكدا ما اذا كان سيئة أو جميلة، لكنه يتيح لك إنشاء مشغل "السحرية" التي تسمح لك لتفريغ القيم المرجعة متعددة في متغير الخاصة بهم. يتم تعريف rel="noreferrer"> وظيفة := ، وشملت أدناه ل أجيال القادمة:

':=' <- 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

وأنا لا أعرف كيف تشعر حيال ذلك. ربما قد تجد أنه من المفيد في مساحة العمل التفاعلية. استخدامه لبناء (إعادة) مكتبات صالحة للاستعمال (للاستهلاك الجماهيري) قد لا يكون أفضل فكرة، ولكن أعتقد أن الامر متروك لكم.

... أنت تعرف ماذا يقولون عن المسؤولية والسلطة ...

وعادة ما التفاف الإخراج إلى القائمة وهي مرنة جدا (هل يمكن أن يكون أي مجموعة من الأرقام، سلاسل، ناقلات، المصفوفات، المصفوفات، والقوائم، والأشياء الباحث انه المخرجات)

وذلك مثل:

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
functionReturningTwoValues <- function() { 
  results <- list()
  results$first <- 1
  results$second <-2
  return(results) 
}
a <- functionReturningTwoValues()

وأعتقد أن هذه الأعمال.

ولقد وضعت حزمة R zeallot لمعالجة هذه المشكلة. يشمل 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, ..)

وتحقق من حزمة href="https://cran.r-project.org/web/packages/zeallot/vignettes/unpacking-assignment.html" المصغر للحصول على مزيد من المعلومات والأمثلة على ذلك.

لا توجد إجابة صحيحة على هذا السؤال.أنا أعتمد حقًا على ما تفعله بالبيانات.في المثال البسيط أعلاه، أود أن أقترح بشدة ما يلي:

  1. أبقِ الأمور بسيطة قدر الإمكان.
  2. كلما كان ذلك ممكنًا، من أفضل الممارسات الحفاظ على توجيه وظائفك.وهذا يوفر أكبر قدر من المرونة والسرعة على المدى الطويل.

هل من المهم أن يكون للقيمتين 1 و2 أعلاه أسماء؟بمعنى آخر، لماذا من المهم في هذا المثال تسمية 1 و2 a وb، بدلاً من r[1] وr[2] فقط؟أحد الأشياء المهمة التي يجب فهمها في هذا السياق هو أن a وb هما أيضًا كلا المتجهين بطول 1.لذا فأنت لا تغير حقًا أي شيء في عملية إجراء هذه المهمة، بخلاف وجود متجهين جديدين لا يحتاجان إلى اشتراكات للرجوع إليها:

> 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

وقوائم يبدو مثاليا لهذا الغرض. على سبيل المثال ضمن الدالة سيكون لديك

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

ونعم لأسئلتك الثانية والثالثة - وهذا ما عليك القيام به كما لا يمكن أن يكون لديك عدة "lvalues" على الجهة اليسرى من واجب

وماذا عن استخدام تعيين؟

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.

[A] إذا كان كل من فو والشريط هو رقم واحد، ثم هناك شيء خاطئ مع ج (فو، بار). ويمكنك أيضا تسمية المكونات: ج (فو = فو، بار = بار). لذلك يمكن أن الوصول إلى عناصر من 'الدقة' النتيجة كما الدقة [1]، قرار [2]. أو، في حالة الكشف عن اسمه، كما الدقة [ "فو"]، قرار [ "BAR"].

[B] إذا فو وشريط ناقلات من نفس النوع والطول، ثم مرة أخرى لا يوجد شيء خاطئ مع عودة cbind (فو، بار) أو rbind (فو، بار). كذلك nameable. في حالة "cbind"، هل الوصول فو وبار كما الدقة [1]، قرار [2] أو الدقة [ "فو"]، قرار [، "بار"]. قد تفضل أيضا للعودة إلى dataframe بدلا من مصفوفة:

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

والوصول إليها كما الدقة $ فو، الدقة $ بار. وهذا من شأنه أيضا العمل بشكل جيد إذا كان فو وشريط من نفس الطول ولكن ليس من نفس النوع (على سبيل المثال فو متجه من الأرقام، منع ناقلات من سلاسل الأحرف).

[C] إذا فو وشريط مختلفة بما فيه الكفاية عدم الجمع ملائم على النحو الوارد أعلاه، فإنك بالتأكيد الإحساس من إرجاع قائمة.

وعلى سبيل المثال، قد الدالة تناسب النموذج الخطي و أيضا حساب القيم المتوقعة، لذلك يمكن أن يكون

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

إذا كنت ترغب في العودة لإخراج الدالة على البيئة العالمية، يمكنك استخدام 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

لحصول على نواتج متعددة من وظيفة والاحتفاظ بها في الشكل المطلوب يمكنك حفظ المخرجات على القرص الثابت (في دليل العمل) من ضمن الدالة ثم تحميلها من خارج الدالة:

myfun <- function(x) {
                      df1 <- ...
                      df2 <- ...
                      save(df1, file = "myfile1")
                      save(df2, file = "myfile2")
}
load("myfile1")
load("myfile2")
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top