1
votes

Alright, I'm trying to replace the use of a nested for loop paired with another for loop with some purrr mapping functions and I'm just not finding it. What I have is a list of dataframes and I know that at least one column in each dataframe contains a match with data in another dataframe not in the list. What I need is to find the columns in the dataframes contained in the list that hold the values that match the values in the external dataframe and rename those columns in the dataframes contained in the list.

To be clear, the dataframes are all of varying numbers of rows, and the data I'm looking for in the list of dfs and the dataframe I'm checking against are hundreds of thousands of random string values - it's not as simple as my example below makes it seem, but the example paints the picture.

Here's a play version of my data.

library(dplyr)
x <- data.frame(first = c(1:3, 6:7),
                second = c(1:3, 6:7),
                third = c(1:5))

y <- data.frame(differ = c(10:13),
                other = c(10:13),
                nomatch = rep(5),
                another = c(10:13),
                argh = c(9:12))

z <- data.frame(nothing = c(20:27),
                nope = c(20:27),
                noway = c(16,17, 18, 19, 5, 21, 22, 23),
                still = c(21:28),
                again = c(22:29))

frame_list <- list(first = x, 
                   second = y, 
                   third = z)

check_against <- data.frame(checking = rep(5, times = 5))

col_name_list <- list()

for (i in 1:length(frame_list)) {
  for (j in 1:length(frame_list[[i]])) {
    if (sum(!(is.na(frame_list[[i]][[j]])) 
            & frame_list[[i]][[j]] 
            %in% check_against[[1]]) > 0) {
      col_name_list[[i]] <- names(frame_list[[i]][j])
    }
  }
}

for (i in 1:length(frame_list)) {
  frame_list[[i]] <- rename(frame_list[[i]],
                            I_want_this_one = col_name_list[[i]])
}

This gets me what I want, but I would love to replace this with purrr or apply functions.

I've tried a couple of things that don't do anything helpful at all:

library(purrr)

map(frame_list, names) %>% 
  imap(., unlist(.), function(x, y) {if (sum(!(is.na(x[[y]])) 
                           & x[[y]] 
                           %in% check_against[[1]]) > 0) {
    col_name_list[[y]] <- names(x[[y]])
    
  }
    x[[y]] <- rename(x[[y]],
                    I_want_this_one = col_name_list[[y]])
    })

# or this
map(frame_list, unlist) %>% 
  imap(., names(.), function(x, y) {if (sum(!(is.na(x[[y]])) 
                                             & x[[y]] 
                                             %in% check_against[[1]]) > 0) {
    col_name_list[[y]] <- names(x[[y]])
    
  }
    x[[y]] <- rename(x[[y]],
                     I_want_this_one = col_name_list[[y]])
  })

I'm having a hard time wrapping my head around a functional approach to accomplishing this.

Any suggestions are greatly appreciated!

1

1 Answers

0
votes

For the first purrr call, give the frame_list, and for the second one, give it the names of the data table. I added a blah column to dataframe y, also changed

library(dplyr)
x <- data.frame(first = c(1:3, 6:7),
                second = c(1:3, 6:7),
                third = c(1:5))

y <- data.frame(differ = c(10:13),
                other = c(10:13),
                nomatch = rep(5),
                blah=rep(5),
                another = c(10:13),
                argh = c(9:12))

z <- data.frame(nothing = c(20:27),
                nope = c(20:27),
                noway = c(16,17, 18, 19, 5, 21, 22, 23),
                still = c(21:28),
                again = c(22:29))

frame_list <- list(first = x, 
                   second = y, 
                   third = z)

check_against <- rep(5, 5)

col_name_list=purrr::map(frame_list, function(w) {
  m=purrr::map_lgl(w, function(x) {
    return(any(unlist(x) %in% check_against))
  })
  names(w)[m]
})

col_name_list

output

$first
[1] "third"

$second
[1] "nomatch" "blah"   

$third
[1] "noway"