0
votes

I found this code line below on SO and it worked as a charm outside a function to identify the list of dataframes and join them using rbind.

    mylist<-ls(pattern='leg_')
    mleg <- do.call(rbind, lapply(mylist, get))

But when I enclose this within a loop, I am getting an error message. I have tried to troubleshoot at various steps in the functions and those work but I might be missing something that is causing this error.

            for(i in 1:(length(blg_idx))){
                assign(paste(deparse(substitute(leg_)),i,sep=''),l_merge(get(paste(deparse(substitute(blg)),i,sep='')),get(paste(deparse(substitute(bsg)),i,sep=''))))
            }

            mylist<-ls(pattern='leg_')

            #return(mylist) # this returns a good list of dataframes

            #mlegleg <- rbind(leg_1,leg_2) # this works 

            mleg <- do.call(rbind, lapply(mylist, get))

            return(mleg)
            } #end function read_leg

            Error in FUN(c("leg_1", "leg_2")[[1L]], ...) : 
              object 'leg_1' not found

When I return mylist from the function, it is able to identify all the dataframes and list them. The function is able to return leg_1 or leg_2 dataframe when I choose to return those in debugging.

            [1] "leg_1" "leg_2"

Any help?

update

I found another of achieving what I need but I am sure it is inefficient although my list of dataframes is a maximum of 4

            for(i in 1:(length(blg_idx))){
                assign(paste(deparse(substitute(leg_)),i,sep=''),l_merge(get(paste(deparse(substitute(blg)),i,sep='')),get(paste(deparse(substitute(bsg)),i,sep=''))))
            }

            mylist<-ls(pattern='leg_')

            #return(mylist)
            #mlegleg <- rbind(leg_1,leg_2) # this works 
            # mleg <- do.call(rbind, lapply(mylist, get))

            mleg <- leg_1

            for(i in 2:(length(blg_idx))){
                mleg <- rbind(leg,get(paste(deparse(substitute(leg_)),i,sep='')))
            }   

            return(mleg)
            } #end read_leg

update 2

Here is the reproducible example for the issue I am facing. For some reason do.call & get is unable to process the mylist parameter generated for dataframes generated within a function.

    read_date <- function(x){
    pur_1 <- data.frame(sku=859, X = sample(1:10),Y = sample(c("yes", "no"), 10, replace = TRUE))
    pur_2 <- data.frame(sku=859, X = sample(11:20),Y = sample(c("yes", "no","na"), 10, replace = TRUE))

    mylist<-ls(pattern='pur_')

    pur_final <- do.call(rbind, lapply(mylist, get))
    #fancier version that I want to achieve is below
    #assign(paste('pur_',eval(pur_1$sku[1]),sep=''),do.call(rbind, lapply(mylist, get)))
    return(pur_final)
}

read_date()

Error message is

read_date() Error in FUN(c("pur_1", "pur_2")[[1L]], ...) : object 'pur_1' not found

update 3 I am sorry for unconventional management of this post but I will get better with my next ones.

Here is what I stumbled upon that is working for me with an exception.

pur_final <- do.call(rbind, mget(paste0("pur_", 1:2),envir = as.environment(-1)))

But the next not so big issue is to suppress the row.names that get added to the dataframe. Any suggestions to suppress the row.names in this context.

    >   read_date()
             sku  X   Y
    pur_1.1  859  8 yes
    pur_1.2  859  4  no
    pur_1.3  859  3 yes
    ....
    pur_2.8  859 14  na
    pur_2.9  859 13  na
    pur_2.10 859 19  no
    >  
3

3 Answers

2
votes

You do not have a reproducible example with which to test this solution but take a look at the help page for get and try this:

mleg <- do.call(rbind, lapply(mylist, get, envir = globalenv() ))
0
votes

The answer above contains the key to your question: envir = globalenv() It took me a while to realize that R will create a private environment for each function. And within that private environment your other variables don't exist. That is, unless you tell your function to look in the Global Environment by using the envir argument.

Here's a function that should take a character string as input and then identify all variables (e.g. data frames) in Global Environment that include that string of text in their name. Then it will try to bind those variables (data frames).

If all variables are data frames with the same column names, then it should return a single binded data frame. myBindedDF <- mergeCompatibleTables("mypattern")

bindCompatibleTables <- function(x){
  if(is.character(x)){
  mylist <-   grep(x, ls(pos = 1), value=T)
  mergedDF <- do.call(rbind,  mget(mylist,envir = as.environment(1)))

  return(bindedDF)
  } else {
    stop("Input is not a character string")
  }
}
0
votes

A late response but I just faced a similar issue to the update 2 posting where "object 'pur_1' not found".

If you want to use the following within a function when you have an unknown number of dataframes starting with "pur_", for example:

mylist <- ls(pattern='pur_')
mleg <- do.call(rbind, lapply(mylist, get))

Then you need to point to the correct environment within the function:

mylist <- ls(pattern='pur_')
mleg <- do.call(rbind, lapply(mylist, get, env=environment()))