FUN के अंदर लंग्ली इंडेक्स नामों तक पहुंचें


162

क्या मेरे lapply () फ़ंक्शन में सूची इंडेक्स नाम प्राप्त करने का एक तरीका है?

n = names(mylist)
lapply(mylist, function(list.elem) { cat("What is the name of this list element?\n" })

मैंने पहले पूछा कि क्या यह संभव है कि लिपीली () लौटी हुई सूची में सूचकांक के नामों को संरक्षित किया जाए , लेकिन मुझे अभी भी नहीं पता है कि क्या कस्टम फ़ंक्शन के अंदर प्रत्येक तत्व का नाम लाने का एक आसान तरीका है। मैं खुद नामों पर लप्पीली कॉल करने से बचना चाहूंगा, मैं फंक्शन पैरामीटर में नाम लेना चाहूंगा।


विशेषताओं के साथ एक और चाल है। यहाँ देखें: stackoverflow.com/questions/4164960/… जो कि DWin के समान है, लेकिन अलग है। :)
रोमन लुसट्रिक

जवाबों:


161

दुर्भाग्य से, lapplyकेवल आपको वेक्टर के तत्व प्रदान करते हैं जो आप इसे पास करते हैं। सामान्य कार्य-आस-पास इसे वेक्टर के बजाय वेक्टर के नाम या सूचकांक को पास करना है।

लेकिन ध्यान दें कि आप हमेशा फ़ंक्शन के लिए अतिरिक्त तर्क पास कर सकते हैं, इसलिए निम्न कार्य करता है:

x <- list(a=11,b=12,c=13) # Changed to list to address concerns in commments
lapply(seq_along(x), function(y, n, i) { paste(n[[i]], y[[i]]) }, y=x, n=names(x))

यहाँ मैं lapplyके सूचकांकों का उपयोग करता हूं x, लेकिन में xऔर इसके नाम भी पास करता हूं x। जैसा कि आप देख सकते हैं, फ़ंक्शन तर्कों का क्रम कुछ भी हो सकता है - अतिरिक्त lapplyतत्वों के बीच निर्दिष्ट नहीं किए गए पहले तर्क के लिए "तत्व" (यहां सूचकांक) में पास होगा । इस मामले में, मैं निर्दिष्ट करता हूं yऔर n, इसलिए केवल iबचा हुआ है ...

जो निम्नलिखित उत्पादन करता है:

[[1]]
[1] "a 11"

[[2]]
[1] "b 12"

[[3]]
[1] "c 13"

अद्यतन सरल उदाहरण, एक ही परिणाम:

lapply(seq_along(x), function(i) paste(names(x)[[i]], x[[i]]))

यहां फ़ंक्शन "ग्लोबल" चर का उपयोग करता है xऔर प्रत्येक कॉल में नाम निकालता है।


कस्टम फ़ंक्शन में 'i' पैरामीटर कैसे आरंभ किया जाता है?
रॉबर्ट कुब्रिक

मिल गया है, इसलिए बहुत () वास्तव में seq_along द्वारा दिए गए तत्वों पर लागू होता है। मैं भ्रमित हो गया क्योंकि कस्टम फ़ंक्शन मापदंडों को फिर से व्यवस्थित किया गया था। आमतौर पर पुनरावृत्त सूची तत्व पहला पैरामीटर है।
रॉबर्ट कुब्रिक

अपडेट किया गया जवाब और बदल पहला समारोह का उपयोग करने के yबजाय xइतना है कि यह (उम्मीद) स्पष्ट समारोह में यह तर्क कुछ भी फोन कर सकते हैं। साथ ही वेक्टर मान भी बदले 11,12,13
टॉमी

@RobertKubrick - हाँ, मैंने शायद एक ही बार में बहुत सी चीजें दिखाने की कोशिश की है ... आप तर्कों को कुछ भी नाम दे सकते हैं और उन्हें किसी भी क्रम में रख सकते हैं।
टॉमी

@ - मुझे लगता है कि यह सही है (और सूचियों पर भी लागू होता है) ;-) ... लेकिन कृपया मुझे गलत साबित करें!
टॉमी

48

यह मूल रूप से टॉमी के समान वर्कअराउंड का उपयोग करता है, लेकिन इसके साथ Map(), वैश्विक चर तक पहुंचने की कोई आवश्यकता नहीं है जो सूची घटकों के नामों को संग्रहीत करते हैं।

> x <- list(a=11, b=12, c=13)
> Map(function(x, i) paste(i, x), x, names(x))
$a
[1] "a 11"

$b
[1] "b 12"

$c
[1] "c 13

या, यदि आप चाहें mapply()

> mapply(function(x, i) paste(i, x), x, names(x))
     a      b      c 
"a 11" "b 12" "c 13"

यह निश्चित रूप से गुच्छा का सबसे अच्छा समाधान है।
emilBeBri

उपयोग mapply()करते SIMPLIFYसमय, विकल्प पर ध्यान दें , जो सत्य के लिए चूक है। मेरे मामले में, इसने पूरी चीज को एक बड़े मैट्रिक्स में बना दिया जब मैं केवल एक साधारण सूची के लिए आवेदन करना चाहता था। इसे F(अंदर mapply()) सेट करना इसे इच्छानुसार चलाया।
ट्रांसजेंसी के लिए जे जे और

39

R संस्करण 3.2 के लिए अद्यतन

डिस्क्लेमर: यह एक हैकिंग ट्रिक है, और अगले रिलीज़ में काम करना बंद कर सकता है।

आप इसका उपयोग करके सूचकांक प्राप्त कर सकते हैं:

> lapply(list(a=10,b=20), function(x){parent.frame()$i[]})
$a
[1] 1

$b
[1] 2

नोट: []इसे काम करने के लिए आवश्यक है, क्योंकि यह आर को यह सोचकर चकरा देता है कि प्रतीक i(मूल्यांकन फ्रेम में lapply) का अधिक संदर्भ हो सकता है, इस प्रकार यह आलसी दोहराव को सक्रिय करता है। इसके बिना, R अलग प्रतियां नहीं रखेगा i:

> lapply(list(a=10,b=20), function(x){parent.frame()$i})
$a
[1] 2

$b
[1] 2

अन्य विदेशी चाल का उपयोग किया जा सकता है, जैसे function(x){parent.frame()$i+0}या function(x){--parent.frame()$i}

प्रदर्शन प्रभाव

क्या जबरन दोहराव प्रदर्शन हानि का कारण होगा? हाँ! यहाँ बेंचमार्क हैं:

> x <- as.list(seq_len(1e6))

> system.time( y <- lapply(x, function(x){parent.frame()$i[]}) )
user system elapsed
2.38 0.00 2.37
> system.time( y <- lapply(x, function(x){parent.frame()$i[]}) )
user system elapsed
2.45 0.00 2.45
> system.time( y <- lapply(x, function(x){parent.frame()$i[]}) )
user system elapsed
2.41 0.00 2.41
> y[[2]]
[1] 2

> system.time( y <- lapply(x, function(x){parent.frame()$i}) )
user system elapsed
1.92 0.00 1.93
> system.time( y <- lapply(x, function(x){parent.frame()$i}) )
user system elapsed
2.07 0.00 2.09
> system.time( y <- lapply(x, function(x){parent.frame()$i}) )
user system elapsed
1.89 0.00 1.89
> y[[2]]
[1] 1000000

निष्कर्ष

यह उत्तर केवल यह दर्शाता है कि आपको इसका उपयोग नहीं करना चाहिए ... न केवल आपका कोड अधिक पठनीय होगा यदि आपको टॉमी के ऊपर एक और समाधान मिलता है, और भविष्य के रिलीज के साथ अधिक संगत है, तो आप कोर टीम को कड़ी मेहनत करने वाले अनुकूलन को खोने का जोखिम भी उठाते हैं। विकसित!


पुराने संस्करणों की चाल, अब काम नहीं कर रही:

> lapply(list(a=10,b=10,c=10), function(x)substitute(x)[[3]])

परिणाम:

$a
[1] 1

$b
[1] 2

$c
[1] 3

स्पष्टीकरण: lapplyफॉर्म आदि की कॉल बनाता है FUN(X[[1L]], ...), FUN(X[[2L]], ...)इसलिए यह तर्क पास हो जाता है कि लूप में करंट इंडेक्स X[[i]]कहां iहै। यदि हमें इसका मूल्यांकन करने से पहले मिलता है (यानी, यदि हम उपयोग करते हैं substitute), तो हमें बिना मूल्यांकन के अभिव्यक्ति मिलती है X[[i]]। यह [[फ़ंक्शन के लिए एक कॉल है , जिसमें तर्क X(एक प्रतीक) और i(एक पूर्णांक) है। तो substitute(x)[[3]]यह पूर्णांक ठीक देता है।

इंडेक्स होने पर, आप नामों को तुच्छ रूप से एक्सेस कर सकते हैं, यदि आप इसे इस तरह से पहले बचाते हैं:

L <- list(a=10,b=10,c=10)
n <- names(L)
lapply(L, function(x)n[substitute(x)[[3]]])

परिणाम:

$a
[1] "a"

$b
[1] "b"

$c
[1] "c"

या इस दूसरी चाल का उपयोग कर: :-)

lapply(list(a=10,b=10,c=10), function(x)names(eval(sys.call(1)[[2]]))[substitute(x)[[3]]])

(परिणाम वही है)।

स्पष्टीकरण 2: sys.call(1)रिटर्न lapply(...), ताकि sys.call(1)[[2]]सूची तर्क के रूप में इस्तेमाल किया अभिव्यक्ति है lapply। इसे पास करना evalएक वैध वस्तु बनाता है जो namesएक्सेस कर सकता है। मुश्किल है, लेकिन यह काम करता है।

बोनस: नाम पाने का दूसरा तरीका:

lapply(list(a=10,b=10,c=10), function(x)eval.parent(quote(names(X)))[substitute(x)[[3]]])

ध्यान दें कि Xपैरेंट फ़्रेम में एक मान्य ऑब्जेक्ट है FUN, और सूची तर्क का संदर्भ देता है lapply, इसलिए हम इसके साथ मिल सकते हैं eval.parent


2
कोड lapply(list(a=10,b=10,c=10), function(x)substitute(x)[[3]])सभी के लिए लौट रहा है 3. क्या आप बताएंगे कि यह 3 कैसे चुना गया था? और विसंगति का कारण? क्या यह इस मामले में सूची की लंबाई के बराबर है, 3. क्षमा करें यदि यह एक मूल प्रश्न है, लेकिन यह जानना चाहते हैं कि इसे सामान्य मामले में कैसे लागू किया जाए।
अनुषा

@ अनुषा, वास्तव में, वह फॉर्म अब काम नहीं कर रहा है ... लेकिन lapply(list(a=10,b=10,c=10), function(x)eval.parent(quote(names(X)))[substitute(x)[[3]]])काम करता है ... मैं जांच करूंगा कि क्या चल रहा है।
फर्डिनेंड.क्राफ्ट

@ फर्डिनेंड.क्राफ्ट, lapply(list(a=10,b=10,c=10), function(x)eval.parent(quote(names(X)))[substitute(x)[[3]]])अब काम नहीं कर रहा है, और एक त्रुटि देता है, Error in eval.parent(quote(names(X)))[substitute(x)[[3]]] : invalid subscript type 'symbol'क्या इसे ठीक करने का एक आसान तरीका है?
फोरकास्टर

@ Ferdinand.kraft बहुत बहुत शुक्रिया
भविष्यवक्ता

18

मुझे एक ही समस्या बहुत बार हुई है ... मैंने दूसरे तरीके का उपयोग करना शुरू कर दिया है ... उपयोग करने के बजाय lapply, मैंने उपयोग करना शुरू कर दिया हैmapply

n = names(mylist)
mapply(function(list.elem, names) { }, list.elem = mylist, names = n)

2
मैं भी इसे पसंद करता हूं, लेकिन यह उत्तर पिछले एक की नकल है ।
मर्व

13

आप पैकेज imap()से उपयोग करने का प्रयास कर सकते हैं purrr

प्रलेखन से:

imap (x, ...) मैप 2 के लिए छोटा हाथ है (x, नाम (x), ...) यदि x के नाम हैं, या map2 (x, seq_along (x), ...) यदि ऐसा नहीं है।

तो, आप इसे इस तरह से उपयोग कर सकते हैं:

library(purrr)
myList <- list(a=11,b=12,c=13) 
imap(myList, function(x, y) paste(x, y))

जो आपको निम्नलिखित परिणाम देगा:

$a
[1] "11 a"

$b
[1] "12 b"

$c
[1] "13 c"

10

बस नामों में लूप है।

sapply(names(mylist), function(n) { 
    doSomething(mylist[[n]])
    cat(n, '\n')
}

यह निश्चित रूप से सबसे सरल उपाय है।
मक्खियों

1
@flies: हाँ, यह mylistफ़ंक्शन के अंदर हार्ड-कोड चर के लिए बुरा अभ्यास को छोड़कर है । बेहतर अभी भी करने के लिएfunction(mylist, nm) ...
smci

5

टॉमी का जवाब नामित वैक्टर पर लागू होता है, लेकिन मुझे लगता है कि आप सूचियों में रुचि रखते थे। और ऐसा लगता है जैसे वह एक अंत के आसपास कर रहे थे क्योंकि वह कॉलिंग वातावरण से "x" का संदर्भ दे रहा था। यह फ़ंक्शन केवल उन मापदंडों का उपयोग करता है जो फ़ंक्शन को पास किए गए थे और इसलिए उन वस्तुओं के नाम के बारे में कोई धारणा नहीं है जो पारित किए गए थे:

x <- list(a=11,b=12,c=13)
lapply(x, function(z) { attributes(deparse(substitute(z)))$names  } )
#--------
$a
NULL

$b
NULL

$c
NULL
#--------
 names( lapply(x, function(z) { attributes(deparse(substitute(z)))$names  } ))
#[1] "a" "b" "c"
 what_is_my_name <- function(ZZZ) return(deparse(substitute(ZZZ)))
 what_is_my_name(X)
#[1] "X"
what_is_my_name(ZZZ=this)
#[1] "this"
 exists("this")
#[1] FALSE

आपका फंक्शन ही लौटता है NULL?! तो lapply(x, function(x) NULL)एक ही जवाब देता है ...
टॉमी

ध्यान दें कि lapplyहमेशा xपरिणाम के बाद से नाम जोड़ता है ।
टॉमी

हाँ। सहमत हूं कि इस अभ्यास का सबक है।
IRTFM

4

मेरा जवाब टॉमी और कैराकल के समान है, लेकिन एक अतिरिक्त ऑब्जेक्ट के रूप में सूची को बचाने से बचा जाता है।

lapply(seq(3), function(i, y=list(a=14,b=15,c=16)) { paste(names(y)[[i]], y[[i]]) })

परिणाम:

[[1]]
[1] "a 14"

[[2]]
[1] "b 15"

[[3]]
[1] "c 16"

यह सूची को FUN के बजाय एक नामांकित तर्क के रूप में देता है (lapply के बजाय)। lapply को केवल सूची के तत्वों पर पुनरावृत्त होना है (सूची की लंबाई बदलते समय lapply के लिए इस पहले तर्क को बदलने के लिए सावधान रहें)।

नोट: सूची को सीधे एक अतिरिक्त तर्क के रूप में स्पष्ट रूप से देने का भी काम करता है:

lapply(seq(3), function(i, y) { paste(names(y)[[i]], y[[i]]) }, y=list(a=14,b=15,c=16))

3

@Caracals और @ टॉमी दोनों अच्छे समाधान हैं और यह ands और list´s सहित एक उदाहरण है data.frame
rएक है listकी listहै और data.frameहै ( dput(r[[1]]अंत में)।

names(r)
[1] "todos"  "random"
r[[1]][1]
$F0
$F0$rst1
   algo  rst  prec  rorac prPo pos
1  Mean 56.4 0.450 25.872 91.2 239
6  gbm1 41.8 0.438 22.595 77.4 239
4  GAM2 37.2 0.512 43.256 50.0 172
7  gbm2 36.8 0.422 18.039 85.4 239
11 ran2 35.0 0.442 23.810 61.5 239
2  nai1 29.8 0.544 52.281 33.1 172
5  GAM3 28.8 0.403 12.743 94.6 239
3  GAM1 21.8 0.405 13.374 68.2 239
10 ran1 19.4 0.406 13.566 59.8 239
9  svm2 14.0 0.385  7.692 76.2 239
8  svm1  0.8 0.359  0.471 71.1 239

$F0$rst5
   algo  rst  prec  rorac prPo pos
1  Mean 52.4 0.441 23.604 92.9 239
7  gbm2 46.4 0.440 23.200 83.7 239
6  gbm1 31.2 0.416 16.421 79.5 239
5  GAM3 28.8 0.403 12.743 94.6 239
4  GAM2 28.2 0.481 34.815 47.1 172
11 ran2 26.6 0.422 18.095 61.5 239
2  nai1 23.6 0.519 45.385 30.2 172
3  GAM1 20.6 0.398 11.381 75.7 239
9  svm2 14.4 0.386  8.182 73.6 239
10 ran1 14.0 0.390  9.091 64.4 239
8  svm1  6.2 0.370  3.584 72.4 239

उद्देश्य unlistसभी सूचियों का है, listमामले की पहचान करने के लिए कॉलम के रूप में as नामों का क्रम डालते हैं ।

r=unlist(unlist(r,F),F)
names(r)
[1] "todos.F0.rst1"  "todos.F0.rst5"  "todos.T0.rst1"  "todos.T0.rst5"  "random.F0.rst1" "random.F0.rst5"
[7] "random.T0.rst1" "random.T0.rst5"

सूचियों को सूचीबद्ध करें लेकिन nots नहीं data.frame

ra=Reduce(rbind,Map(function(x,y) cbind(case=x,y),names(r),r))

Mapस्तंभ के रूप में नामों का क्रम रखता है। Reduceसभी data.frame´s से जुड़ें ।

head(ra)
            case algo  rst  prec  rorac prPo pos
1  todos.F0.rst1 Mean 56.4 0.450 25.872 91.2 239
6  todos.F0.rst1 gbm1 41.8 0.438 22.595 77.4 239
4  todos.F0.rst1 GAM2 37.2 0.512 43.256 50.0 172
7  todos.F0.rst1 gbm2 36.8 0.422 18.039 85.4 239
11 todos.F0.rst1 ran2 35.0 0.442 23.810 61.5 239
2  todos.F0.rst1 nai1 29.8 0.544 52.281 33.1 172

पुनश्च r[[1]]:

    structure(list(F0 = structure(list(rst1 = structure(list(algo = c("Mean", 
    "gbm1", "GAM2", "gbm2", "ran2", "nai1", "GAM3", "GAM1", "ran1", 
    "svm2", "svm1"), rst = c(56.4, 41.8, 37.2, 36.8, 35, 29.8, 28.8, 
    21.8, 19.4, 14, 0.8), prec = c(0.45, 0.438, 0.512, 0.422, 0.442, 
    0.544, 0.403, 0.405, 0.406, 0.385, 0.359), rorac = c(25.872, 
    22.595, 43.256, 18.039, 23.81, 52.281, 12.743, 13.374, 13.566, 
    7.692, 0.471), prPo = c(91.2, 77.4, 50, 85.4, 61.5, 33.1, 94.6, 
    68.2, 59.8, 76.2, 71.1), pos = c(239L, 239L, 172L, 239L, 239L, 
    172L, 239L, 239L, 239L, 239L, 239L)), .Names = c("algo", "rst", 
    "prec", "rorac", "prPo", "pos"), row.names = c(1L, 6L, 4L, 7L, 
    11L, 2L, 5L, 3L, 10L, 9L, 8L), class = "data.frame"), rst5 = structure(list(
        algo = c("Mean", "gbm2", "gbm1", "GAM3", "GAM2", "ran2", 
        "nai1", "GAM1", "svm2", "ran1", "svm1"), rst = c(52.4, 46.4, 
        31.2, 28.8, 28.2, 26.6, 23.6, 20.6, 14.4, 14, 6.2), prec = c(0.441, 
        0.44, 0.416, 0.403, 0.481, 0.422, 0.519, 0.398, 0.386, 0.39, 
        0.37), rorac = c(23.604, 23.2, 16.421, 12.743, 34.815, 18.095, 
        45.385, 11.381, 8.182, 9.091, 3.584), prPo = c(92.9, 83.7, 
        79.5, 94.6, 47.1, 61.5, 30.2, 75.7, 73.6, 64.4, 72.4), pos = c(239L, 
        239L, 239L, 239L, 172L, 239L, 172L, 239L, 239L, 239L, 239L
        )), .Names = c("algo", "rst", "prec", "rorac", "prPo", "pos"
    ), row.names = c(1L, 7L, 6L, 5L, 4L, 11L, 2L, 3L, 9L, 10L, 8L
    ), class = "data.frame")), .Names = c("rst1", "rst5")), T0 = structure(list(
        rst1 = structure(list(algo = c("Mean", "ran1", "GAM1", "GAM2", 
        "gbm1", "svm1", "nai1", "gbm2", "svm2", "ran2"), rst = c(22.6, 
        19.4, 13.6, 10.2, 9.6, 8, 5.6, 3.4, -0.4, -0.6), prec = c(0.478, 
        0.452, 0.5, 0.421, 0.423, 0.833, 0.429, 0.373, 0.355, 0.356
        ), rorac = c(33.731, 26.575, 40, 17.895, 18.462, 133.333, 
        20, 4.533, -0.526, -0.368), prPo = c(34.4, 52.1, 24.3, 40.7, 
        37.1, 3.1, 14.4, 53.6, 54.3, 116.4), pos = c(195L, 140L, 
        140L, 140L, 140L, 195L, 195L, 140L, 140L, 140L)), .Names = c("algo", 
        "rst", "prec", "rorac", "prPo", "pos"), row.names = c(1L, 
        9L, 3L, 4L, 5L, 7L, 2L, 6L, 8L, 10L), class = "data.frame"), 
        rst5 = structure(list(algo = c("gbm1", "ran1", "Mean", "GAM1", 
        "GAM2", "svm1", "nai1", "svm2", "gbm2", "ran2"), rst = c(17.6, 
        16.4, 15, 12.8, 9, 6.2, 5.8, -2.6, -3, -9.2), prec = c(0.466, 
        0.434, 0.435, 0.5, 0.41, 0.8, 0.44, 0.346, 0.345, 0.337), 
            rorac = c(30.345, 21.579, 21.739, 40, 14.754, 124, 23.2, 
            -3.21, -3.448, -5.542), prPo = c(41.4, 54.3, 35.4, 22.9, 
            43.6, 2.6, 12.8, 57.9, 62.1, 118.6), pos = c(140L, 140L, 
            195L, 140L, 140L, 195L, 195L, 140L, 140L, 140L)), .Names = c("algo", 
        "rst", "prec", "rorac", "prPo", "pos"), row.names = c(5L, 
        9L, 1L, 3L, 4L, 7L, 2L, 8L, 6L, 10L), class = "data.frame")), .Names = c("rst1", 
    "rst5"))), .Names = c("F0", "T0"))

0

मान लें कि हम प्रत्येक तत्व की लंबाई की गणना करना चाहते हैं।

mylist <- list(a=1:4,b=2:9,c=10:20)
mylist

$a
[1] 1 2 3 4

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

$c
 [1] 10 11 12 13 14 15 16 17 18 19 20

यदि उद्देश्य केवल परिणामी तत्वों को लेबल करना है, तो lapply(mylist,length)नीचे या काम करता है।

sapply(mylist,length,USE.NAMES=T)

 a  b  c 
 4  8 11 

यदि उद्देश्य फ़ंक्शन के अंदर लेबल का उपयोग करना है, तो mapply()दो वस्तुओं पर लूपिंग करके उपयोगी है; सूची तत्वों और नामों की सूची।

fun <- function(x,y) paste0(length(x),"_",y)
mapply(fun,mylist,names(mylist))

     a      b      c 
 "4_a"  "8_b" "11_c" 

0

@ फर्डिनेंड-क्राफ्ट ने हमें एक शानदार ट्रिक दी और फिर हमें बताया कि हमें इसका उपयोग नहीं करना चाहिए क्योंकि यह अनिर्दिष्ट है और ओवरहेड प्रदर्शन के कारण।

मैं पहले बिंदु के साथ बहुत बहस नहीं कर सकता, लेकिन मैं यह नोट करना चाहूंगा कि ओवरहेड को शायद ही कभी चिंता का विषय होना चाहिए।

चलो सक्रिय कार्यों को परिभाषित करते हैं, इसलिए हमें जटिल अभिव्यक्ति को कॉल करने की आवश्यकता नहीं है , parent.frame()$i[]लेकिन केवल .i(), हम .n()नाम तक पहुंचने के लिए भी बनाएंगे , जो आधार और purrr फंक्शंस (और शायद अन्य सभी के रूप में अच्छी तरह से) के लिए काम करना चाहिए ।

.i <- function() parent.frame(2)$i[]
# looks for X OR .x to handle base and purrr functionals
.n <- function() {
  env <- parent.frame(2)
  names(c(env$X,env$.x))[env$i[]]
}

sapply(cars, function(x) paste(.n(), .i()))
#>     speed      dist 
#> "speed 1"  "dist 2"

अब एक सरल फ़ंक्शन को बेंचमार्क करते हैं, जो अलग-अलग दृष्टिकोणों का उपयोग करके एक वेक्टर के आइटम को उनके सूचकांक में चिपकाता है (यह संचालन बेशक उपयोग करके वेक्टर किया जा सकता है, paste(vec, seq_along(vec))लेकिन यहां बात नहीं है)।

हम एक बेंचमार्किंग फ़ंक्शन और प्लॉटिंग फ़ंक्शन को परिभाषित करते हैं और नीचे दिए गए परिणामों को प्लॉट करते हैं:

library(purrr)
library(ggplot2)
benchmark_fun <- function(n){
  vec <- sample(letters,n, replace = TRUE)
  mb <- microbenchmark::microbenchmark(unit="ms",
                                      lapply(vec, function(x)  paste(x, .i())),
                                      map(vec, function(x) paste(x, .i())),
                                      lapply(seq_along(vec), function(x)  paste(vec[[x]], x)),
                                      mapply(function(x,y) paste(x, y), vec, seq_along(vec), SIMPLIFY = FALSE),
                                      imap(vec, function(x,y)  paste(x, y)))
  cbind(summary(mb)[c("expr","mean")], n = n)
}

benchmark_plot <- function(data, title){
  ggplot(data, aes(n, mean, col = expr)) + 
    geom_line() +
    ylab("mean time in ms") +
    ggtitle(title) +
    theme(legend.position = "bottom",legend.direction = "vertical")
}

plot_data <- map_dfr(2^(0:15), benchmark_fun)
benchmark_plot(plot_data[plot_data$n <= 100,], "simplest call for low n")

benchmark_plot(plot_data,"simplest call for higher n")

2019-11-15 को रेप्रेक्स पैकेज (v0.3.0) द्वारा बनाया गया

पहले चार्ट की शुरुआत में गिरावट एक अस्थायी है, कृपया इसे अनदेखा करें।

हम देखते हैं कि चुना हुआ उत्तर वास्तव में तेज है, और पुनरावृत्तियों की एक सभ्य मात्रा के लिए हमारे .i()समाधान वास्तव में धीमे हैं, चुने हुए उत्तर की तुलना में ओवरहेड उपयोग करने के ओवरहेड के लगभग 3 गुना है purrr::imap(), और 30k पुनरावृत्तियों के लिए 25 मि। इसलिए मैं प्रति 1000 पुनरावृत्तियों में 1 एमएस, 1 मिलियन प्रति सेकंड खो देता हूं। मेरी राय में सुविधा के लिए यह एक छोटी सी लागत है।


-1

बस अपना स्वयं का कस्टम lapplyफ़ंक्शन लिखें

lapply2 <- function(X, FUN){
  if( length(formals(FUN)) == 1 ){
    # No index passed - use normal lapply
    R = lapply(X, FUN)
  }else{
    # Index passed
    R = lapply(seq_along(X), FUN=function(i){
      FUN(X[[i]], i)
    })
  }

  # Set names
  names(R) = names(X)
  return(R)
}

तो इस तरह का उपयोग करें:

lapply2(letters, function(x, i) paste(x, i))

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