1

I have a list of data.frames. I want to send each data.frame to a function using lapply. Inside the function I want to check whether the name of a data.frame includes a particular string. If the string in question is present I want to perform one series of operations. Otherwise I want to perform a different series of operations. I cannot figure out how to check whether the string in question is present from within the function.

I wish to use base R. This seems to be a possible solution but I cannot get it to work:

In R, how to get an object's name after it is sent to a function?

Here is an example list followed by an example function further below.

matrix.apple1 <- read.table(text = '
     X3   X4   X5
      1    1    1
      1    1    1
', header = TRUE)
matrix.apple2 <- read.table(text = '
     X3   X4   X5
      1    1    1
      2    2    2
', header = TRUE)
matrix.orange1 <- read.table(text = '
     X3   X4   X5
     10   10   10
     20   20   20
', header = TRUE)
my.list <- list(matrix.apple1  = matrix.apple1,
                matrix.orange1 = matrix.orange1,
                matrix.apple2  = matrix.apple2)

This operation can check whether each object name contains the string apples but I am not sure how to use this information inside the function further below.

grepl('apple', names(my.list), fixed = TRUE)
#[1]  TRUE FALSE  TRUE

Here is an example function. Based on hours of searching and trial-and-error I perhaps am supposed to use deparse(substitute(x)) but so far it only returns x or something similar.

table.function <- function(x) {

     # The three object names are:
     # 'matrix.apple1', 'matrix.orange1' and 'matrix.apple2'
     myObjectName <- deparse(substitute(x))
     print(myObjectName)

     # perform a trivial example operation on a data.frame
     my.table <- table(as.matrix(x))

     # Test whether an object name contains the string 'apple'
     contains.apple <- grep('apple', myObjectName, fixed = TRUE)

     # Use the result of the above test to perform a trivial example operation.
     # With my code 'my.binomial' is always given the value of 0 even though
     # 'apple' appears in the name of two of the data.frames.
     my.binomial <- ifelse(contains.apple == 1, 1, 0)

     return(list(my.table = my.table, my.binomial = my.binomial))
        
}

table.function.output <- lapply(my.list, function(x) table.function(x))

These are the results of print(myObjectName):

#[1] "x"
#[1] "x"
#[1] "x"

table.function.output

Here are the rest of the results of table.function showing that my.binomial is always 0. The first and third value of my.binomial should be 1 because the names of the first and third data.frames contain the string apple.

# $matrix.apple1
# $matrix.apple1$my.table
# 1 
# 6 
# $matrix.apple1$my.binomial
# logical(0)
# 
# $matrix.orange1
# $matrix.orange1$my.table
# 10 20 
#  3  3 
# $matrix.orange1$my.binomial
# logical(0)
# 
# $matrix.apple2
# $matrix.apple2$my.table
# 1 2 
# 3 3 
# $matrix.apple2$my.binomial
# logical(0)
1

2 Answers 2

2

You could redesign your function to use the list names instead:

table_function <- function(myObjectName) {
  # The three object names are:
  # 'matrix.apple1', 'matrix.orange1' and 'matrix.apple2'
  myObject <- get(myObjectName)
  
  print(myObjectName)
  
  # perform a trivial example operation on a data.frame
  my.table <- table(as.matrix(myObject))
  
  # Test whether an object name contains the string 'apple'
  contains.apple <- grep('apple', myObjectName, fixed = TRUE)
  
  # Use the result of the above test to perform a trivial example operation.
  # With my code 'my.binomial' is always given the value of 0 even though
  # 'apple' appears in the name of two of the data.frames.
  my.binomial <- +(contains.apple == 1)
  
  return(list(my.table = my.table, my.binomial = my.binomial))
  
}


lapply(names(my.list), table_function)

This returns

[[1]]
[[1]]$my.table

1 
6 

[[1]]$my.binomial
[1] 1


[[2]]
[[2]]$my.table

10 20 
 3  3 

[[2]]$my.binomial
integer(0)


[[3]]
[[3]]$my.table

1 2 
3 3 

[[3]]$my.binomial
[1] 1

If you want to keep the list names, you could use

sapply(names(my.list), table_function, simplify = FALSE, USE.NAMES = TRUE)

instead of lapply.

Sign up to request clarification or add additional context in comments.

Comments

1

Use Map and pass both list data and it's name to the function. Change your function to accept two arguments.

table.function <- function(data, name) {
  
  # The three object names are:
  # 'matrix.apple1', 'matrix.orange1' and 'matrix.apple2'
  print(name)
  
  # perform a trivial example operation on a data.frame
  my.table <- table(as.matrix(data))
  
  # Test whether an object name contains the string 'apple'
  contains.apple <- grep('apple', name, fixed = TRUE)
  
  # Use the result of the above test to perform a trivial example operation.
  # With my code 'my.binomial' is always given the value of 0 even though
  # 'apple' appears in the name of two of the data.frames.
  my.binomial <- as.integer(contains.apple == 1)
  
  return(list(my.table = my.table, my.binomial = my.binomial))
}

Map(table.function, my.list, names(my.list))

#[1] "matrix.apple1"
#[1] "matrix.orange1"
#[1] "matrix.apple2"
#$matrix.apple1
#$matrix.apple1$my.table

#1 
#6 

#$matrix.apple1$my.binomial
#[1] 1


#$matrix.orange1
#$matrix.orange1$my.table

#10 20 
# 3  3 

#$matrix.orange1$my.binomial
#integer(0)
#...
#...

The same functionality is provided by imap in purrr where you don't need to explicitly pass the names.

purrr::imap(my.list, table.function)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.