David Vaillette
David Vaillette

Reputation: 11

Getting a NULL return from a 0 row dataframe

I have a function that sometimes returns a value of NULL and sometimes returns a data frame with 0 rows. I would like do something else. Say that object x is an object that can be NULL or 0 rows

x1 <- some operation on x
if(is.null(x) & is.null(x1) { do stuff }

I'm trying to think of a way to query a data frame that will return NULL if it has 0 rows and will return something that is not NULL if it has any rows. That is because the following does not work:

while(is.null(x) | dim(x)[1] == 0) { do stuff }

because when x is null you get a argument is of length zero error when you query dim(x)

Every thing I can think of returns <NA> and not NULL. Actually I think my code would look like

while(is.null(x) & is.null(some.operation(x)) { do stuff }

Upvotes: 1

Views: 465

Answers (3)

David Vaillette
David Vaillette

Reputation: 11

I came up with a solution of:

makeNull<-function(x){
  if(is.null(x)) {return(x)}
  if(dim(x)[1]==0) {x<-NULL}
  x
}

so then I would enter

while(is.null(x)&is.null(makeNull(x)){do stuff}

to replace

while(is.null(x)|dim(x)[1]){do stuff}

Upvotes: 0

lmo
lmo

Reputation: 38500

This function will return NULL if the data.frame has 0 rows or the number of rows if the data.frame is has at least one row.

myFunc <- function(x) return(list(NULL, nrow(x))[[(!(is.null(nrow(x) > 0))) + 1L]])

I use list to encapsulate NULL as an element that can be returned. The second element of the list is the number of rows Then, the proper list element is returned with [[.

Here are a couple of test examples

# NULL input
myFunc(NULL)
NULL
# empty data.frame
myFunc(data.frame())
NULL
# data.frame with single element
myFunc(data.frame(a=1))
# data.frame with vector of length 10
[1] 1
myFunc(data.frame(a=1:10))
[1] 10

Upvotes: 0

csgillespie
csgillespie

Reputation: 60462

If I understand your question correctly, then you just need to change

while(is.null(x)|dim(x)[1]==0){do stuff}

to

while(is.null(x) || dim(x)[1]==0){do stuff}

The logical OR (|) operator is vectorised. This both sides are always evaluated, e.g. we always evaluate is.null(x) and dim(x).

In contrast, the operator || works for scalers (actually it also works on vectors, but only uses the first value). This means that we only evaluate dim(x) if is.null(x) returns FALSE.

For example

# Vectorised, so stop is called
TRUE | stop("Now!")
#Error: Now!

with

# Scaler: stop is not evaluated.
TRUE || stop("Now!")
#[1] TRUE

Upvotes: 3

Related Questions