सूची तत्व मौजूद होने पर परीक्षण कैसे करें?


113

संकट

मैं परीक्षण करना चाहूंगा कि क्या किसी सूची का एक तत्व मौजूद है, तो यहां एक उदाहरण है

foo <- list(a=1)
exists('foo') 
TRUE   #foo does exist
exists('foo$a') 
FALSE  #suggests that foo$a does not exist
foo$a
[1] 1  #but it does exist

इस उदाहरण में, मुझे पता है कि foo$aमौजूद है, लेकिन परीक्षण वापस आ गया FALSE

मैंने अंदर देखा ?existsऔर पाया कि with(foo, exists('a')रिटर्न TRUE, लेकिन समझ में नहीं आता कि exists('foo$a')रिटर्न क्यों FALSE

प्रशन

  • क्यों exists('foo$a')लौटता है FALSE?
  • with(...)पसंदीदा दृष्टिकोण का उपयोग है ?

1
शायद !is.null(foo$a)(या !is.null(foo[["a"]])सुरक्षित पक्ष पर होने के लिए)? (या exists("a",where=foo))
बेन बोल्कर

1
@BenBolker धन्यवाद - एक अच्छा जवाब देगा; बाद वाला विकल्प क्यों पसंद किया जाता है?
डेविड लेबॉयर

3
@ दाविद आंशिक मिलान ... उपरोक्त के साथfoo <- list(a1=1)
बैपटिस्ट

जवाबों:


151

यह वास्तव में थोड़ा मुश्किल है जितना आप सोचते हैं। चूंकि एक सूची वास्तव में (कुछ प्रयास के साथ) में NULL तत्व होते हैं, इसलिए यह जांचने के लिए पर्याप्त नहीं हो सकता है is.null(foo$a)। यह जांचने के लिए अधिक कठोर परीक्षण हो सकता है कि नाम वास्तव में सूची में परिभाषित किया गया है:

foo <- list(a=42, b=NULL)
foo

is.null(foo[["a"]]) # FALSE
is.null(foo[["b"]]) # TRUE, but the element "exists"...
is.null(foo[["c"]]) # TRUE

"a" %in% names(foo) # TRUE
"b" %in% names(foo) # TRUE
"c" %in% names(foo) # FALSE

... और foo[["a"]]अधिक सुरक्षित है foo$a, क्योंकि उत्तरार्द्ध आंशिक मिलान का उपयोग करता है और इस प्रकार यह एक लंबे नाम से भी मेल खा सकता है:

x <- list(abc=4)
x$a  # 4, since it partially matches abc
x[["a"]] # NULL, no match

[अद्यतन] तो, सवाल पर वापस क्यों exists('foo$a')काम नहीं करता है। existsसमारोह केवल चेक के एक चर एक वातावरण में मौजूद रहने पर, नहीं तो एक वस्तु अस्तित्व के कुछ हिस्सों। स्ट्रिंग "foo$a"की व्याख्या साहित्यिक है: क्या "foo $ a" नामक एक चर है? ... और जवाब है FALSE...

foo <- list(a=42, b=NULL) # variable "foo" with element "a"
"bar$a" <- 42   # A variable actually called "bar$a"...
ls() # will include "foo" and "bar$a" 
exists("foo$a") # FALSE 
exists("bar$a") # TRUE

2
यह अभी भी स्पष्ट नहीं है - क्या कोई कारण है exists('foo$a') == FALSE?
डेविड लेबॉयर

यह सुझाव देता है कि आर में इसके लिए कोई अच्छा उपाय नहीं है! एक और अधिक जटिल चीजें (जैसे कि अगर $mylist[[12]]$out$mcerrorपरिभाषित किया गया है) परीक्षण करना चाहते हैं जो वर्तमान में नरक के रूप में जटिल होगा।
TMS

क्या आप @ जिम के उत्तर में दिए गए whereतर्क के बारे में जानते हैं ? exists
डेविड लेबॉयर

"bar$a" <- 42मैं वास्तव में चाहता हूं कि यह अमान्य सिंटैक्स था और मौजूद है ("फू $ ए") भोलेपन में काम किया।
एंडी वी

44

नामित तत्वों की जांच करने का सबसे अच्छा तरीका उपयोग करना है exist(), हालांकि उपरोक्त उत्तर ठीक से फ़ंक्शन का उपयोग नहीं कर रहे हैं। आपको सूची के भीतरwhere चर की जांच करने के लिए तर्क का उपयोग करने की आवश्यकता है ।

foo <- list(a=42, b=NULL)

exists('a', where=foo) #TRUE
exists('b', where=foo) #TRUE
exists('c', where=foo) #FALSE

8
exists()किसी सूची का उपयोग करने से काम चल जाता है, लेकिन मेरा मानना ​​है कि R उस नाम की एक वस्तु की जाँच करने से पहले आंतरिक रूप से इसे एक पर्यावरण के लिए ज़ब्त करता है, जो अक्षम है और कोई भी अनाम तत्व होने पर त्रुटियों का परिणाम हो सकता है। उदाहरण के लिए यदि आप चलाने के लिए exists('a', list(a=1, 2)), यह एक त्रुटि दे देंगे: Error in list2env(list(a = 1, 2), NULL, <environment>) : attempt to use zero-length variable name। रूपांतरण यहाँ होता है: github.com/wch/r-source/blob/…
wch

5

यहां अन्य उत्तरों में प्रस्तावित विधियों की प्रदर्शन तुलना है।

> foo <- sapply(letters, function(x){runif(5)}, simplify = FALSE)
> microbenchmark::microbenchmark('k' %in% names(foo), 
                                 is.null(foo[['k']]), 
                                 exists('k', where = foo))
Unit: nanoseconds
                     expr  min   lq    mean median   uq   max neval cld
      "k" %in% names(foo)  467  933 1064.31    934  934 10730   100  a 
      is.null(foo[["k"]])    0    0  168.50      1  467  3266   100  a 
 exists("k", where = foo) 6532 6998 7940.78   7232 7465 56917   100   b

यदि आप कई बार पहुंच वाले तेज़ शब्दकोश के रूप में सूची का उपयोग करने की योजना बना रहे हैं, तो is.nullदृष्टिकोण एकमात्र व्यवहार्य विकल्प हो सकता है। मेरा मानना ​​है कि यह O (1) है, जबकि %in%दृष्टिकोण O (n) है?


4

@ Salient.salamander का एक मामूली संशोधित संस्करण, यदि कोई पूर्ण पथ पर जांच करना चाहता है, तो इसका उपयोग किया जा सकता है।

Element_Exists_Check = function( full_index_path ){
  tryCatch({
    len_element = length(full_index_path)
    exists_indicator = ifelse(len_element > 0, T, F)
      return(exists_indicator)
  }, error = function(e) {
    return(F)
  })
}

3

एक समाधान जो अभी तक नहीं आया है, वह लंबाई का उपयोग कर रहा है, जो सफलतापूर्वक NULL को संभालता है। जहां तक ​​मैं बता सकता हूं, NULL को छोड़कर सभी मानों की लंबाई 0 से अधिक है।

x <- list(4, -1, NULL, NA, Inf, -Inf, NaN, T, x = 0, y = "", z = c(1,2,3))
lapply(x, function(el) print(length(el)))
[1] 1
[1] 1
[1] 0
[1] 1
[1] 1
[1] 1
[1] 1
[1] 1
[1] 1
[1] 1
[1] 3

इस प्रकार हम एक सरल कार्य कर सकते हैं जो नामांकित और गिने हुए दोनों सूचकांकों के साथ काम करता है:

element.exists <- function(var, element)
{
  tryCatch({
    if(length(var[[element]]) > -1)
      return(T)
  }, error = function(e) {
    return(F)
  })
}

यदि तत्व मौजूद नहीं है, तो यह tryCatch ब्लॉक द्वारा पकड़ी गई एक बाहरी सीमा की स्थिति का कारण बनता है।


3

rlang::has_name() यह भी कर सकते हैं:

foo = list(a = 1, bb = NULL)
rlang::has_name(foo, "a")  # TRUE
rlang::has_name(foo, "b")  # FALSE. No partial matching
rlang::has_name(foo, "bb")  # TRUE. Handles NULL correctly
rlang::has_name(foo, "c")  # FALSE

जैसा कि आप देख सकते हैं, यह स्वाभाविक रूप से उन सभी मामलों को संभालता है जो @Tommy ने दिखाया था कि आधार R का उपयोग कैसे किया जाता है और अनाम वस्तुओं के साथ सूचियों के लिए काम करता है। मैं अभी भी exists("bb", where = foo)पठनीयता के लिए एक अन्य उत्तर में प्रस्तावित के रूप में सिफारिश करूंगा , लेकिन has_nameयदि आपके पास अनाम आइटम हैं तो एक विकल्प है।


0

एक सूची तत्व purrr::has_elementके मूल्य के खिलाफ जांच करने के लिए उपयोग करें :

> x <- list(c(1, 2), c(3, 4))
> purrr::has_element(x, c(3, 4))
[1] TRUE
> purrr::has_element(x, c(3, 5))
[1] FALSE

क्या यह काम करता है यदि तत्व घोंसले के शिकार / घोंसले के किसी भी स्तर पर है? मैंने डॉक्स की जाँच की और यह स्पष्ट नहीं था
डेविड लेबॉयर

@DavidLeBauer, नहीं। उस स्थिति में, मैं rapply(कुछ इस तरह any(rapply(x, function(v) identical(v, c(3, 4)), how = 'unlist')))
दिमित्री ज़ोटिकोव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.