Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

replace list elements (avoid global assignment)

Tags:

r

I lave a non-nested list (pretty straight forward). Some elements are NAs but can be replaced with other elements from the same list. I can achieve this with the global assignment operator <<-. However I'm trying to learn better practice (As this appears to give me notes when compiling a package for CRAN). Questions:

  1. Can I achieve this without a global assignment?
  2. If not how can I use assign appropriately (my approach seems to make a bunch of copies of the same data set and may run into memory issues).

I have tried assign and it doesn't work. I also tried to use lapply without global assignment but I can only get the last element returned rather than the list with each element replaced.

Here's the problem:

#Fake Data
L1 <- lapply(1:3, function(i) rnorm(1))
L1[4:5] <- NA
names(L1) <- letters[1:5]

#items to replace and their replacements (names of elements to replace)
nulls <- names(L1[sapply(L1, function(x) is.na(x))])
replaces <- c("b", "a")

#doesn't work (returns only last element)
lapply(seq_along(nulls), function(i) {
    L1[[nulls[i]]] <- L1[[replaces[i]]]
    return(L1)
})

#works but considered bad practice by many
lapply(seq_along(nulls), function(i) {
    L1[[nulls[i]]] <<- L1[[replaces[i]]]
})

#does not work (I try L1[["d"]] and still get NA)
lapply(seq_along(nulls), function(i) {
    assign(paste0("L1[[", nulls[i], "]]"), L1[[replaces[i]]], envir = .GlobalEnv)
})

#also bad practice bu I tried
lapply(seq_along(nulls), function(i) {
    assign(paste0("L1$", nulls[i]), L1[[replaces[i]]], envir = .GlobalEnv)
})

#This works but it feels like we're making a ton of copies of the same data set
lapply(seq_along(nulls), function(i) {
    L1[[nulls[i]]] <- L1[[replaces[i]]]
    assign("L1", L1, envir = .GlobalEnv)
})  

Ultimately, I'd like to do this without global assignment but if not that what is best practice for a for CRAN build of a package.

like image 942
Tyler Rinker Avatar asked Jan 14 '13 15:01

Tyler Rinker


2 Answers

There's a replace function that will do this for you:

replace(L1, match(nulls, names(L1)), L1[match(replaces, names(L1))])

You could also use the slightly simpler which(is.na(L1)), instead of match(nulls, names(L1))

like image 115
Matthew Plourde Avatar answered Nov 03 '22 00:11

Matthew Plourde


For completeness here's hadley's suggestion of a for loop as some similar circumstances wouldn't allow for using replace:

for(i in seq_along(a[!apps])){
    L1[[nulls[i]]] <- L1[[replaces[i]]]
}
like image 4
Tyler Rinker Avatar answered Nov 03 '22 01:11

Tyler Rinker