This can be tricky, because depending on what the missing object is, you can get
either NULL, NA, or an error. Moreover is.na() behaves differently when
evaluated on its own, or as the condition of an if() statement. Here is a
function that may make life easier. The goal is NOT to have to pass extra
arguments.
- I use try() and return FALSE if the evaluation returns an error.
This applies to objects that are not found, incorrect syntax etc.
- List elements that don't exist are NULL and return FALSE.
- If any elements are NA, return FALSE. This handles out-of-bounds
elements AND out-of-bounds slices on vectors. But it would also
trip on valid vectors that contain an NA. I can't think of a good
way to distinguish these two cases right now. The "best" way for
this depends on the context.
I think I am handling the most obvious special cases - though I do expect this
can be improved.
is.valid <- function(x,
na.ignore = FALSE,
null.ignore=FALSE) {
# errors are always FALSE
if (class(try(x, silent=TRUE)) == "try-error") return(FALSE)
# NULL is FALSE except if ignored
if (is.null(x)) {
if (!null.ignore) return(FALSE)
return(TRUE)
}
# If all elments are NA, return FALSE except if ignored;
if (any(is.na(x))) {
if (!na.ignore) return(FALSE)
return(TRUE)
}
# Everything else is TRUE
return(TRUE)
}
# Test cases
is.valid(1) # TRUE: valid numeric constant
is.valid(FALSE) # TRUE: valid boolean constant
is.valid(nonSuch) # FALSE: object doesn't exist
x <- 1:5;
is.valid(x) # TRUE: existing variable
is.valid(x[4]) # TRUE: vector element
is.valid(x[8]) # FALSE: out of bounds: NA
is.valid(x[5:6]) # FALSE: partially out of bounds: (5, NA)
is.valid(x[8], na.ignore=TRUE) # TRUE
x[3] <- NA
is.valid(x) # FALSE: no element can be NA
is.valid(x, na.ignore=TRUE) # TRUE
m <- matrix(1:9,nrow=3, ncol=3)
is.valid(m[2,2]) # TRUE
is.valid(m[2,4]) # FALSE: subscript out of bounds
is.valid(m[2,2,2]) # FALSE: incorrect n of dimensions
l <- list(first=7, letters, NULL)
is.valid(l[["first"]]) # TRUE: existing list elements
is.valid(l[[4]]) # FALSE: list element does not exist
is.valid(l[[2]][27]) # FALSE: out of bounds on existing element
is.valid(l$first) # TRUE:
is.valid(l$second) # FALSE: non-existent element: NULL
is.valid(l$second, null.ignore=TRUE) # TRUE
Cheers,
B.
On Dec 20, 2014, at 11:20 AM, Rui Barradas <ruipbarradas at sapo.pt>
wrote:
> Hello,
>
> Your list seems to have only 2 elements. You can check this with
>
> length(x)
>
> Or you can try
>
> lapply(x, is.null)
>
> Hope this helps,
>
> Rui Barradas
>
> Em 20-12-2014 15:58, Ragia Ibrahim escreveu:
>> Hello,
>> Kindly I have a list of lists as follow
>> x
>> [[1]]
>> [1] 7
>>
>> [[2]]
>> [1] 3 4 5
>>
>> as showen x[[3]] does not have a value and it has NULL, how can I check
on this
>> how to test if x[[3]] is empty.
>>
>> thanks in advance
>> Ragia
>>
>> [[alternative HTML version deleted]]
>>
>> ______________________________________________
>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>> https://stat.ethz.ch/mailman/listinfo/r-help
>> PLEASE do read the posting guide
http://www.R-project.org/posting-guide.html
>> and provide commented, minimal, self-contained, reproducible code.
>>
>
> ______________________________________________
> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide
http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
Boris et. al: Indeed, corner cases are a bear, which is why it is incumbent on any OP to precisely define what they mean by, say, "missing", "null","empty", etc. Here is an evil example to illustrate the sorts of nastiness that can occur:> z <- list(a=NULL, b=list(), c=NA)> with(z,{+ c(identical(a,b), + identical(a,c), + identical(b,c) + ) + }) [1] FALSE FALSE FALSE ## OK, none of these three are "the same" in the sense of identical(). But ...> outer(z,z,identical)Error in outer(z, z, identical) : dims [product 9] do not match the length of object [1] ## outer gets completely flummoxed, as it should!> expand.grid(z,z)Var1 Var2 1 NULL NULL 2 NULL NULL 3 NA NULL 4 NULL NULL 5 NULL NULL 6 NA NULL 7 NULL NA 8 NULL NA 9 NA NA ## and expand.grid gets confused, as it probably should. :-) Cheers, Bert Bert Gunter Genentech Nonclinical Biostatistics (650) 467-7374 "Data is not information. Information is not knowledge. And knowledge is certainly not wisdom." Clifford Stoll On Sat, Dec 20, 2014 at 10:57 AM, Boris Steipe <boris.steipe at utoronto.ca> wrote:> This can be tricky, because depending on what the missing object is, you can get either NULL, NA, or an error. Moreover is.na() behaves differently when evaluated on its own, or as the condition of an if() statement. Here is a function that may make life easier. The goal is NOT to have to pass extra arguments. > > - I use try() and return FALSE if the evaluation returns an error. > This applies to objects that are not found, incorrect syntax etc. > - List elements that don't exist are NULL and return FALSE. > - If any elements are NA, return FALSE. This handles out-of-bounds > elements AND out-of-bounds slices on vectors. But it would also > trip on valid vectors that contain an NA. I can't think of a good > way to distinguish these two cases right now. The "best" way for > this depends on the context. > > I think I am handling the most obvious special cases - though I do expect this can be improved. > > > is.valid <- function(x, > na.ignore = FALSE, > null.ignore=FALSE) { > > # errors are always FALSE > if (class(try(x, silent=TRUE)) == "try-error") return(FALSE) > > # NULL is FALSE except if ignored > if (is.null(x)) { > if (!null.ignore) return(FALSE) > return(TRUE) > } > > # If all elments are NA, return FALSE except if ignored; > if (any(is.na(x))) { > if (!na.ignore) return(FALSE) > return(TRUE) > } > > # Everything else is TRUE > return(TRUE) > } > > > > # Test cases > is.valid(1) # TRUE: valid numeric constant > is.valid(FALSE) # TRUE: valid boolean constant > is.valid(nonSuch) # FALSE: object doesn't exist > > x <- 1:5; > is.valid(x) # TRUE: existing variable > is.valid(x[4]) # TRUE: vector element > is.valid(x[8]) # FALSE: out of bounds: NA > is.valid(x[5:6]) # FALSE: partially out of bounds: (5, NA) > > is.valid(x[8], na.ignore=TRUE) # TRUE > > x[3] <- NA > is.valid(x) # FALSE: no element can be NA > is.valid(x, na.ignore=TRUE) # TRUE > > > m <- matrix(1:9,nrow=3, ncol=3) > is.valid(m[2,2]) # TRUE > is.valid(m[2,4]) # FALSE: subscript out of bounds > is.valid(m[2,2,2]) # FALSE: incorrect n of dimensions > > l <- list(first=7, letters, NULL) > is.valid(l[["first"]]) # TRUE: existing list elements > is.valid(l[[4]]) # FALSE: list element does not exist > is.valid(l[[2]][27]) # FALSE: out of bounds on existing element > is.valid(l$first) # TRUE: > is.valid(l$second) # FALSE: non-existent element: NULL > is.valid(l$second, null.ignore=TRUE) # TRUE > > > Cheers, > B. > > > > On Dec 20, 2014, at 11:20 AM, Rui Barradas <ruipbarradas at sapo.pt> wrote: > >> Hello, >> >> Your list seems to have only 2 elements. You can check this with >> >> length(x) >> >> Or you can try >> >> lapply(x, is.null) >> >> Hope this helps, >> >> Rui Barradas >> >> Em 20-12-2014 15:58, Ragia Ibrahim escreveu: >>> Hello, >>> Kindly I have a list of lists as follow >>> x >>> [[1]] >>> [1] 7 >>> >>> [[2]] >>> [1] 3 4 5 >>> >>> as showen x[[3]] does not have a value and it has NULL, how can I check on this >>> how to test if x[[3]] is empty. >>> >>> thanks in advance >>> Ragia >>> >>> [[alternative HTML version deleted]] >>> >>> ______________________________________________ >>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see >>> https://stat.ethz.ch/mailman/listinfo/r-help >>> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html >>> and provide commented, minimal, self-contained, reproducible code. >>> >> >> ______________________________________________ >> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see >> https://stat.ethz.ch/mailman/listinfo/r-help >> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html >> and provide commented, minimal, self-contained, reproducible code. > > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.
This may be out of context, but on the face of it, this claim is wrong: On 20/12/2014, 1:57 PM, Boris Steipe wrote: "Moreover is.na() behaves differently when evaluated on its own, or as the condition of an if() statement." The conditions in an if() statement are not evaluated in special conditions at all. The only way you'll get a different value is if the argument to is.na() does tricky stuff like looking at the evaluation stack. Duncan Murdoch
Thanks. This is what I was referring to:
x <- rep(NA, 3)
is.na(x)
[1] TRUE TRUE TRUE
if (is.na(x)) {print("True")}
[1] "True"
Warning message:
In if (is.na(x)) { :
the condition has length > 1 and only the first element will be used
You are of course right - the warning is generated by if(), not by is.na() and
the reason for the warning is that is.na() returns a vector if applied to a
vector. I should have been more clear.
Cheers,
B.
On Dec 20, 2014, at 3:29 PM, Duncan Murdoch <murdoch.duncan at gmail.com>
wrote:
> This may be out of context, but on the face of it, this claim is wrong:
>
> On 20/12/2014, 1:57 PM, Boris Steipe wrote:
> "Moreover is.na() behaves differently when evaluated on its own, or as
> the condition of an if() statement."
>
> The conditions in an if() statement are not evaluated in special
> conditions at all. The only way you'll get a different value is if the
> argument to is.na() does tricky stuff like looking at the evaluation stack.
>
> Duncan Murdoch