একটি ফাংশন যা একাধিক মান ফেরত দেয় তাকে কীভাবে বরাদ্দ করা যায়?


223

এখনও আর যুক্তিতে toোকার চেষ্টা করছি ... একাধিক মূল্যবোধ ফিরিয়ে ফাংশন থেকে ফলাফলগুলি (এলএইচএসে) আনপ্যাক করার "সেরা" উপায় কী?

আমি দৃশ্যত এটি করতে পারি না:

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
এফওয়াইআই, একাধিক মান প্রত্যাবর্তনের আরেকটি উপায় হল attrআপনার রিটার্নের মান সেট করা set
জোনাথন চ্যাং

এটি পাইথনের টিপল-আনপ্যাকিংয়ের সমতুল্য।
স্মিচ

উত্তর:


185

(1) তালিকা [...] <- আমি এই একটি দশকে আগে পোস্ট করেছিলেন R-সাহায্যের । সেই থেকে এটি 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]]যথেষ্ট হবে))

আরও উদাহরণের জন্য উদ্ধৃত আর-সহায়তা থ্রেড দেখুন।

(২) এর সাথে যদি উদ্দেশ্যটি কেবল একাধিক মানকে পরবর্তীতে একত্রিত করা হয় এবং প্রত্যাবর্তনের মানগুলির নামকরণ করা হয় তবে একটি সহজ বিকল্পটি হ'ল 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
@ জি.গ্রোথেনডিক, আমি যদি আপনার উত্তরের লিঙ্কটির বিষয়বস্তু রাখি তবে আপনি কি আপত্তি করবেন? আমি মনে করি এটির পক্ষে এটি ব্যবহার করা সহজতর হবে।
Merlin2011

12
আমি @ Merlin2011 এর সাথে একমত; লিখিত হিসাবে মনে হচ্ছে এই সিনট্যাক্সটি আর বেসে এমবেড করা আছে।
জানু

6
@ জি.গ্রোথেনডেইক আমি মার্লিন ২০১১ এবং জানার সাথে একমত - যদি এখানে গুরুত্বপূর্ণ আসল কোডটি (লিঙ্কে রেফারেন্সীকৃত কোড) উত্তরে থাকে তবে ভাল হবে। ফলাফল অবজেক্টের নাম তালিকার প্রয়োজন নেই বলে উল্লেখ করা খারাপ ধারণা নাও হতে পারে। এটি আপনার আসল কোডটি পড়ার আগে আমাকে কিছুক্ষণের জন্য বিভ্রান্ত করেছিল। যেমনটি বর্ণিত উত্তরটিতে বলা হয়েছে যে আপনাকে লিঙ্কে কোডটি চালানো দরকার তবে বেশিরভাগ লোকেরা সরাসরি কোডটি সরাসরি উত্তরটিতে না পড়তে পারা যায় না - এটি এই ধারণাটি দেয় যে এই বাক্য
গঠনটি

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

আমি জানি না যে আমি এটি সম্পর্কে কেমন অনুভব করি। আপনার ইন্টারেক্টিভ ওয়ার্কস্পেসে সম্ভবত এটি আপনাকে সহায়ক মনে হতে পারে। ব্যবহারযোগ্য লাইব্রেরিগুলি (পুনরায়) ব্যবহারের জন্য এটি (জনসাধারণের জন্য) ব্যবহার করা সেরা ধারণা নাও হতে পারে তবে আমার ধারণা এটি আপনার পক্ষে up

... আপনি জানেন যে তারা দায়িত্ব এবং ক্ষমতা সম্পর্কে কী বলে ...


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) এর পরিবর্তে আমি দুটি বস্তুতে ফলাফল পেতে চাই? আমি তালিকাটি চেষ্টা করেছি ("এ", "বি") <-ফুনক 2 (5) তবে এটি কার্যকর হয় না।
স্ক্যান

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

আমি মনে করি এটি কাজ করে।


11

এই সমস্যাটি মোকাবেলায় আমি একটি আর প্যাকেজ জিলোট একসাথে রেখেছি । জেলোট একাধিক অ্যাসাইনমেন্ট বা আনপ্যাকিং অ্যাসাইনমেন্ট অপারেটর %<-%,। অপারেটরের এলএইচএস হ'ল নির্ধারিত সংখ্যক ভেরিয়েবল, কল ব্যবহার করে নির্মিত 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
কোনও বিশেষ সিনট্যাক্সের প্রয়োজন নেই, আপনি সংখ্যার একটি তালিকা হিসাবে প্লট অবজেক্টের একটি তালিকা বরাদ্দ করতে পারেন।
nteetor

10

এই প্রশ্নের সঠিক উত্তর নেই। আপনি ডেটা দিয়ে যা করছেন তার উপরে আমি সত্যিই নির্ভর করি। উপরের সাধারণ উদাহরণে, আমি দৃ strongly়ভাবে পরামর্শ দেব:

  1. জিনিসগুলি যতটা সম্ভব সহজ রাখুন।
  2. যেখানেই সম্ভব, আপনার ক্রিয়াকলাপগুলিকে ভেক্টরাইজ রাখা সবচেয়ে ভাল অনুশীলন। এটি দীর্ঘমেয়াদে সর্বাধিক পরিমাণে নমনীয়তা এবং গতি সরবরাহ করে।

উপরের 1 এবং 2 এর মানগুলির নাম থাকা কি গুরুত্বপূর্ণ? অন্য কথায়, এই উদাহরণে কেন গুরুত্বপূর্ণ যে 1 এবং 2 কেবলমাত্র [[1] এবং আর [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 

[সম্পাদনা] আপনি পৃথকভাবে প্রতিটি ভেক্টরকে ন্যূনতম এবং সর্বাধিক প্রয়োগ করবেন, আমি ম্যাট্রিক্স ব্যবহার করার পরামর্শ দিচ্ছি (যদি 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তাদের জায়গায় আসে তবে তা নয় )।
মারিওটোমো

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") <-returnlist ()? আমি বলছি কারণ তালিকার বেশ কয়েকটি উপাদান যদি আপনাকে পুরো ফাংশনটি কয়েকবার চালানোর প্রয়োজন হয় এবং এতে একটি সময় ব্যয় হয়।
স্ক্যান

4

হ্যাঁ আপনার দ্বিতীয় এবং তৃতীয় প্রশ্নের হ্যাঁ - আপনার একটি অ্যাসাইনমেন্টের বামে একাধিক 'লাভ' থাকতে না পারায় আপনাকে যা করতে হবে তা হ'ল।


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


... তবে এর জন্য আপনাকে সেই পরিবেশের প্রাপ্ত ভেরিয়েবলগুলির নামগুলি জানতে হবে
স্মি

@ এসএমসি হ্যাঁ এজন্য প্রশ্নে "নামযুক্ত তালিকা" পদ্ধতিটি সাধারণতঃ আরও ভাল: r <- function() { return(list(first=1, second=2)) }এবং ফলাফলগুলি ব্যবহার করে r$firstএবং উল্লেখ করে r$second
স্টিভ পিচার্স

2
একবার আপনার ফাংশনটি হয়ে গেলে আপনি কীভাবে উভয় ভেরিয়েবলকে একক কোমন্ডে বরাদ্দ করতে পারবেন, যেমন তালিকার ("x", "y") <- ফাংশন রিটার্নিংটোভ্যালুইস ('a', 'বি')? আমি বলছি কারণ তালিকায় আপনার অনেক উপাদান থাকলে আপনার পুরো ফাংশনটি বেশ কয়েকবার চালানো দরকার এবং এতে একটি সময় ব্যয় হয়
স্ক্যান করুন

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] হিসাবে ফলাফলগুলির উপাদানগুলি অ্যাক্সেস করতে পারবেন; বা, নামকৃত ক্ষেত্রে, "[ফু"] হিসাবে, পুনরায় ["বার"] র করুন।

[বি] যদি foo এবং বার একই ধরণের এবং দৈর্ঘ্যের ভেক্টর হয়, তবে আবার সিবাইন্ড (foo, বার) বা rbind (foo, বার) ফেরার ক্ষেত্রে কোনও ভুল নেই; একইভাবে নামযোগ্য। 'সিবাইন্ড' ক্ষেত্রে, আপনি রেস [, 1], রেস [, 2] বা রেস হিসাবে [, "ফু"], রেস [, "বার"] হিসাবে ফু ও বার অ্যাক্সেস করতে পারবেন। আপনি ম্যাট্রিক্সের চেয়ে ডেটাফ্রেম ফেরত দিতে পছন্দ করতে পারেন:

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

এবং তাদেরকে রেস $ ফু, রেস $ বার হিসাবে অ্যাক্সেস করুন। এটিও কার্যকরভাবে কাজ করতে পারে যদি foo এবং বার একই দৈর্ঘ্যের হয় তবে একই ধরণের না হয় (যেমন foo সংখ্যার ভেক্টর, অক্ষরের স্ট্রিংয়ের একটি ভেক্টর বার করে)।

[সি] উপরের মতো সুবিধাজনকভাবে একত্রিত না হওয়ার জন্য যদি ফু ও বার যথেষ্ট আলাদা হয়, তবে আপনি অবশ্যই একটি তালিকা ফিরিয়ে আনবেন।

উদাহরণস্বরূপ, আপনার ফাংশন একটি রৈখিক মডেল মাপসই করতে পারে এবং পূর্বাভাসিত মানগুলিও গণনা করে, তাই আপনি থাকতে পারেন

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

এবং তারপরে আপনি return list(Foo=foo,Bar=bar)এবং এরপরে Res $ Foo হিসাবে সংক্ষিপ্তসারটি অ্যাক্সেস করতে পারবেন, Res $ বার হিসাবে পূর্বাভাসিত মান

উত্স: http://r.789695.n4.nabble.com/How-to-return-m Multipleple-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

আর 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.