अपने स्वयं के फ़ंक्शन को लिखते समय R की दीर्घवृत्त सुविधा का उपयोग कैसे करें?


186

R भाषा में फ़ंक्शंस को परिभाषित करने के लिए एक निफ्टी फ़ीचर है जो एक चर संख्या में तर्क ले सकता है। उदाहरण के लिए, फ़ंक्शन data.frameकिसी भी तर्क को लेता है, और प्रत्येक तर्क परिणामी डेटा तालिका में एक स्तंभ के लिए डेटा बन जाता है। उदाहरण उपयोग:

> data.frame(letters=c("a", "b", "c"), numbers=c(1,2,3), notes=c("do", "re", "mi"))
  letters numbers notes
1       a       1    do
2       b       2    re
3       c       3    mi

फ़ंक्शन के हस्ताक्षर में एक दीर्घवृत्त शामिल है, जैसे:

function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, 
    stringsAsFactors = default.stringsAsFactors()) 
{
    [FUNCTION DEFINITION HERE]
}

मैं एक फ़ंक्शन लिखना चाहता हूं जो कुछ समान करता है, कई मान ले रहा है और उन्हें एक ही रिटर्न वैल्यू में समेकित कर रहा है (साथ ही कुछ अन्य प्रसंस्करण कर रहा है)। ऐसा करने के लिए, मुझे यह पता लगाने की आवश्यकता है ...कि फ़ंक्शन के भीतर फ़ंक्शन के तर्कों से "अनपैक" कैसे करें । मुझे नहीं पता कि यह कैसे करना है। फ़ंक्शन परिभाषा में संबंधित लाइन data.frameहै object <- as.list(substitute(list(...)))[-1L], जिसका मैं कोई मतलब नहीं बना सकता।

तो मैं फ़ंक्शन के हस्ताक्षर से दीर्घवृत्त को कैसे परिवर्तित कर सकता हूं, उदाहरण के लिए, एक सूची?

अधिक विशिष्ट होने के लिए, मैं get_list_from_ellipsisनीचे दिए गए कोड में कैसे लिख सकता हूं ?

my_ellipsis_function(...) {
    input_list <- get_list_from_ellipsis(...)
    output_list <- lapply(X=input_list, FUN=do_something_interesting)
    return(output_list)
}

my_ellipsis_function(a=1:10,b=11:20,c=21:30)

संपादित करें

ऐसा लगता है कि ऐसा करने के दो संभावित तरीके हैं। वे हैं as.list(substitute(list(...)))[-1L]और list(...)। हालाँकि, ये दोनों एक ही काम नहीं करते हैं। (अंतर के लिए, उत्तर में उदाहरण देखें।) क्या कोई मुझे बता सकता है कि उनके बीच व्यावहारिक अंतर क्या है, और मुझे कौन सा उपयोग करना चाहिए?

जवाबों:


113

मैंने जवाब और टिप्पणियाँ पढ़ीं और मैंने देखा कि कुछ चीजों का उल्लेख नहीं किया गया था:

  1. data.framelist(...)संस्करण का उपयोग करता है । कोड का टुकड़ा:

    object <- as.list(substitute(list(...)))[-1L]
    mrn <- is.null(row.names)
    x <- list(...)

    objectस्तंभ नामों के साथ कुछ जादू xकरने के लिए उपयोग किया जाता है , लेकिन अंतिम बनाने के लिए उपयोग किया जाता है data.frame
    अनवैल्युएटेड ...तर्क के उपयोग के लिए write.csvकोड को देखें जहां match.callइसका उपयोग किया जाता है।

  2. जैसा कि आप डिर्क उत्तर में टिप्पणी परिणाम में लिखते हैं, सूचियों की एक सूची नहीं है। लंबाई 4 की एक सूची है, जो तत्व languageप्रकार हैं। पहली वस्तु एक है symbol- list, दूसरी है अभिव्यक्ति 1:10और इसी तरह। यह बताएं कि [-1L]इसकी आवश्यकता क्यों है: यह symbolप्रदान किए गए तर्कों से उम्मीद को हटा देता है ...(क्योंकि यह हमेशा एक सूची है)।
    जैसा कि डिर्क बताता substituteहै कि "पार्स ट्री अनवैल्युएटेड एक्सप्रेशन"।
    जब आप कॉल करते हैं my_ellipsis_function(a=1:10,b=11:20,c=21:30)तो ..."तर्कों की एक सूची" बनाते हैं : list(a=1:10,b=11:20,c=21:30)और substituteइसे चार तत्वों की सूची बनाते हैं:

    List of 4
    $  : symbol list
    $ a: language 1:10
    $ b: language 11:20
    $ c: language 21:30

    पहले तत्व का नाम नहीं है और यह [[1]]डिर्क उत्तर में है। मैं इस परिणाम का उपयोग कर प्राप्त करता हूं:

    my_ellipsis_function <- function(...) {
      input_list <- as.list(substitute(list(...)))
      str(input_list)
      NULL
    }
    my_ellipsis_function(a=1:10,b=11:20,c=21:30)
  3. ऊपर के रूप में हम यह strजांचने के लिए उपयोग कर सकते हैं कि एक फ़ंक्शन में ऑब्जेक्ट क्या हैं।

    my_ellipsis_function <- function(...) {
        input_list <- list(...)
        output_list <- lapply(X=input_list, function(x) {str(x);summary(x)})
        return(output_list)
    }
    my_ellipsis_function(a=1:10,b=11:20,c=21:30)
     int [1:10] 1 2 3 4 5 6 7 8 9 10
     int [1:10] 11 12 13 14 15 16 17 18 19 20
     int [1:10] 21 22 23 24 25 26 27 28 29 30
    $a
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
       1.00    3.25    5.50    5.50    7.75   10.00 
    $b
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
       11.0    13.2    15.5    15.5    17.8    20.0 
    $c
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
       21.0    23.2    25.5    25.5    27.8    30.0 

    यह ठीक है। substituteसंस्करण देखें :

       my_ellipsis_function <- function(...) {
           input_list <- as.list(substitute(list(...)))
           output_list <- lapply(X=input_list, function(x) {str(x);summary(x)})
           return(output_list)
       }
       my_ellipsis_function(a=1:10,b=11:20,c=21:30)
        symbol list
        language 1:10
        language 11:20
        language 21:30
       [[1]]
       Length  Class   Mode 
            1   name   name 
       $a
       Length  Class   Mode 
            3   call   call 
       $b
       Length  Class   Mode 
            3   call   call 
       $c
       Length  Class   Mode 
            3   call   call 

    है कि हम क्या जरूरत नहीं है। इस तरह की वस्तुओं (जैसे write.csv) से निपटने के लिए आपको अतिरिक्त ट्रिक्स की आवश्यकता होगी ।

यदि आप उपयोग करना चाहते हैं, ...तो आपको इसे शेन जवाब के रूप में उपयोग करना चाहिए, द्वारा list(...)


38

आप दीर्घवृत्त को एक सूची में बदल सकते हैं list(), और फिर उस पर अपना कार्य कर सकते हैं:

> test.func <- function(...) { lapply(list(...), class) }
> test.func(a="b", b=1)
$a
[1] "character"

$b
[1] "numeric"

तो आपका get_list_from_ellipsisकार्य इससे अधिक कुछ नहीं है list

इसके लिए एक वैध उपयोग का मामला उन मामलों में है जहां आप ऑपरेशन के लिए अज्ञात संख्या में वस्तुओं को पारित करना चाहते हैं (जैसा कि आपके उदाहरण में c()या data.frame())। ...जब आप प्रत्येक पैरामीटर को पहले से जानते हैं, तो इसका उपयोग करना एक अच्छा विचार नहीं है , हालांकि, चूंकि यह तर्क स्ट्रिंग में कुछ अस्पष्टता और आगे की जटिलता को जोड़ता है (और फ़ंक्शन हस्ताक्षर को किसी अन्य उपयोगकर्ता के लिए अस्पष्ट बनाता है)। तर्क सूची फ़ंक्शन उपयोगकर्ताओं के लिए प्रलेखन का एक महत्वपूर्ण टुकड़ा है।

अन्यथा, यह उन मामलों के लिए भी उपयोगी है, जब आप अपने स्वयं के फ़ंक्शन तर्क में उन सभी को उजागर किए बिना एक सबफंक्शन के मापदंडों से गुजरना चाहते हैं। यह फ़ंक्शन प्रलेखन में नोट किया जा सकता है।


मैं उप-तर्कों के लिए तर्क के लिए पास-थ्रू के रूप में दीर्घवृत्त का उपयोग करने के बारे में जानता हूं, लेकिन मेरे द्वारा वर्णित तरीके से दीर्घवृत्त का उपयोग करने के लिए आर आदिम के बीच यह भी आम बात है। वास्तव में, दोनों listऔर cकार्य इस तरह से काम करते हैं, लेकिन दोनों ही आदिम हैं, इसलिए मैं आसानी से उनके स्रोत कोड का निरीक्षण नहीं कर सकता कि वे कैसे काम करते हैं।
रयान सी। थॉम्पसन

rbind.data.frameइस तरह से उपयोग करें।
मारेक

5
यदि list(...)पर्याप्त है, तो आर बिल्डिंस जैसे कि इसके बजाय data.frameलंबे फॉर्म का उपयोग क्यों करते हैं as.list(substitute(list(...)))[-1L]?
रेयान सी। थॉम्पसन

1
जैसा कि मैंने नहीं बनाया data.frame , मुझे इसका उत्तर नहीं पता है (यह कहा, मुझे यकीन है कि इसके लिए एक अच्छा कारण है)। मैं list()अपने स्वयं के पैकेज में इस उद्देश्य के लिए उपयोग करता हूं और अभी तक इसके साथ कोई समस्या नहीं है।
शेन

34

बस शेन और डिर्क की प्रतिक्रियाओं को जोड़ना है: तुलना करना दिलचस्प है

get_list_from_ellipsis1 <- function(...)
{
  list(...)
}
get_list_from_ellipsis1(a = 1:10, b = 2:20) # returns a list of integer vectors

$a
 [1]  1  2  3  4  5  6  7  8  9 10

$b
 [1]  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20

साथ में

get_list_from_ellipsis2 <- function(...)
{
  as.list(substitute(list(...)))[-1L]
}
get_list_from_ellipsis2(a = 1:10, b = 2:20) # returns a list of calls

$a
1:10

$b
2:20

जैसा कि यह खड़ा है, या तो संस्करण आपके उद्देश्यों के लिए उपयुक्त दिखाई देता है my_ellipsis_function, हालांकि पहला स्पष्ट रूप से सरल है।


15

आपने आधा जवाब पहले ही दे दिया था। विचार करें

R> my_ellipsis_function <- function(...) {
+   input_list <- as.list(substitute(list(...)))
+ }
R> print(my_ellipsis_function(a=1:10, b=2:20))
[[1]]
list

$a
1:10

$b
11:20

R> 

इसलिए इसने दो तर्कों aऔर bकॉल से लिया और इसे एक सूची में बदल दिया। क्या आपने ऐसा नहीं किया था?


2
जो मैं चाहता हूं वह बिलकुल नहीं। यह वास्तव में सूचियों की सूची को वापस करता हुआ प्रतीत होता है। ध्यान दें [[1]]। इसके अलावा, मैं यह जानना चाहूंगा कि जादू भस्म कैसे as.list(substitute(list(...)))काम करता है।
रयान सी। थॉम्पसन

2
आंतरिक तर्क के आधार पर list(...)एक listवस्तु बनाता है । फिर substitute()निर्विवाद अभिव्यक्ति के लिए पार्स ट्री बनाता है; इस फ़ंक्शन के लिए सहायता देखें। साथ ही आर (या एस) पर एक अच्छा उन्नत पाठ। यह तुच्छ सामान नहीं है।
डर्क एडल्डबुलेटेल

ठीक है, [[-1L]]भाग के बारे में क्या (मेरे सवाल से)? यह नहीं होना चाहिए [[1]]?
रयान सी। थॉम्पसन

3
आपको अनुक्रमण पर पढ़ने की आवश्यकता है। माइनस का अर्थ है 'बहिष्कृत', यानी print(c(1:3)[-1])2 और 3 को ही प्रिंट होगा। यह Lसुनिश्चित करने का एक नया तरीका है कि यह पूर्णांक के रूप में समाप्त होता है, यह आर स्रोतों में बहुत कुछ किया जाता है।
डर्क एडल्डबुलेटेल

7
मैं अनुक्रमण को पढ़ने की जरूरत नहीं है, लेकिन मैं करना आदेश दिए गए हैं दिखाने के उत्पादन के करीब ध्यान देने की जरूरत है। [[1]]और $aसूचकांकों के बीच के अंतर ने मुझे लगता है कि नेस्टेड सूचियों को शामिल किया गया था। लेकिन अब मैं देखता हूं कि वास्तव में आपको जो सूची मिलती है वह मैं चाहता हूं, लेकिन सामने एक अतिरिक्त तत्व के साथ। तो फिर [-1L]समझ में आता है। वैसे भी यह अतिरिक्त पहला तत्व कहां से आता है? और क्या कोई कारण है कि मुझे इसे बस इस्तेमाल करना चाहिए list(...)?
रयान सी। थॉम्पसन

6

यह उम्मीद के मुताबिक काम करता है। निम्नलिखित एक इंटरैक्टिव सत्र है:

> talk <- function(func, msg, ...){
+     func(msg, ...);
+ }
> talk(cat, c("this", "is", "a","message."), sep=":")
this:is:a:message.
> 

समान, एक डिफ़ॉल्ट तर्क को छोड़कर:

> talk <- function(func, msg=c("Hello","World!"), ...){
+     func(msg, ...);
+ }
> talk(cat,sep=":")
Hello:World!
> talk(cat,sep=",", fill=1)
Hello,
World!
>

जैसा कि आप देख सकते हैं, आप अपने फ़ंक्शन के भीतर एक फ़ंक्शन के लिए 'अतिरिक्त' तर्कों को पास करने के लिए इसका उपयोग कर सकते हैं यदि डिफॉल्ट्स वह नहीं हैं जो आप किसी विशेष मामले में चाहते हैं।

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