I have many irregularly named objects whose names, in order to be able to use some other package, I need to set to NULL.
E.g.,
v <- 1
w <- 2
names(v) <- "hello"
names(w) <- "world"
I can write
names(v) <- names(w) <- NULL
but for succinctness I would prefer something like
names(c(v,w)) <- NULL
which however does not work ("Error in names(c(v, w)) <- NULL : could not find function "c<-"). This is not unexpected, of course - from ?names: it is a function "to get or set the names of an object".
One option is to place it in a list and set the names to NULL. It is better not to have multiple objects in the global environment
lst1 <- lapply(list(v = v, w = w), setNames, NULL)
Also, as #joran mentioned, unname can be used as well or as.vector (which remove the attributes)
lst1 <- lapply(list(v = v, w = w), unname)
If the intention is to change the already existing objects,
list2env(lst1, envir = .GlobalEnv)
v
#[1] 1
It is better not to create multiple objects in the global env
Related
I need to create a loop function in which I need to address to subsequent objects which names end with numbers i.e. object1, object 2, object3. So the code should look like this:
object1 <- c(1,2,3,4,5)
object2 <- c(2,3,4,5,6)
object3 <- c(3,4,5,6,7)
for (i in 1:3) {
assign (paste0("new_object",i), mean(object???))
}
So I need a equivalent to just typing
new_object1 <- mean(object1)
new_object2 <- mean(object2)
new_object3 <- mean(object3)
Many thanks in advance!
It would be get to return the values of that object by pasteing the 'i' with the 'object' string
for (i in 1:3) {
assign(paste0("new_object",i), mean(get(paste0('object', i)))
}
But, it is not a recommended way as it is creating new objects in the global env.
Instead, if the intention is to get the mean of all the 'object's,
sapply(mget(paste0("object", 1:3)), mean)
Or if there are more than three, use ls with pattern
sapply(mget(ls(pattern = '^object\\d+$')), mean)
Here, mget returns the value of more than one objects in a list, loop through the list with sapply and apply the mean function on the list element.
Creating objects can also be done from the list with list2env
out <- lapply( mget(ls(pattern = '^object\\d+$')), mean)
names(out) <- paste0('new_', names(out))
list2env(out, .GlobalEnv) # not recommended based on the same reason above
I'm trying to work out how to combine a number of functions into a new function. I have code that determines which functions should be combined, and stores them in a list. Some of the functions share arguments, so I need to eliminate the duplicates before building the new function. The following works:
fun1 <- function(x, y) x + y
fun2 <- function(y, z) z * y
funlist <- list(fun1, fun2)
args <- unlist(lapply(funlist, formals)) ## "x", "y", "y", "z"
args <- args[unique(names(args))] ## "x", "y", "z"
At this point, args is a list with three named elements, "x", "y", and "z". I can pass this to as.pairlist() when I'm building my new function.
However, if the functions in funlist are named, my code breaks:
funlist2 <- list(fun1 = fun1, fun2 = fun1)
args2 <- unlist(lapply(funlist2, formals)) ## "fun1.x", "fun1.y", "fun2.y", "fun2.z"
args2 <- args2[unique(names(args2))] ## "fun1.x", "fun1.y", "fun2.y", "fun2.z"
Here, the name of the function is prepended to the arguments, making every argument unique. If I call formals on individual list element, this doesn't happen:
formals(funlist[[1]])
formals(funlist2[[1]])
## both return the same dotted pair list, $x, $y
The list element names only appear when I'm using lapply. I can fix this with a temporary list that removes the names from funlist2, but I don't understand why this is happening - why does lapply add names to the output of formals?
You should look at the output before the unlist call:
(args2 <- lapply(funlist2, formals))
$fun1
$fun1$x
$fun1$y
$fun2
$fun2$x
$fun2$y
lapply is putting names back on the top level but the names at the next level down are the same, while unlist then concatenates the names at different levels and joins them with periods. In the first instance, unlist didn't see any names at the first level and so didn't need to do any concatenation.
This may or may not be on purpose, but args and args2 are both just named lists without any objects in them... If you were to run your code as such
funlist2 <- list(fun1 = fun1, fun2 = fun1)
args2 <- unlist(lapply(funlist2, function(fun) names(formals(fun))))
args2 <- unique(args2)
Now you have a vector with the unique variable names. You can now (if you wish) make the following list:
lst <- list()
lenght(lst) <- length(args2)
names(lst) <- args2
And together those two blocks of code should be the same as your original code. I don't have an available kernel to run this on so I can't provide outputs sorry.
The apply functions in R are a nice way to simplify for loops to get to an output. Is there an equivalent function that helps one avoid for loops when replacing the values of a vector? This is better understood by example...
# Take this list for example
x = list( list(a=1,b=2), list(a=3,b=4), list(a=5,b=6) )
# To get all of the "a" elements from each list, I can do
vapply(x,"[[",1,"a")
[1] 1 3 5
# If I want to change all of the "a" elements, I cannot do
vapply(x,"[[",1,"a") = 10:12
Error in vapply(x, "[[", 1, "a") = 10:12 :
could not find function "vapply<-"
# (this error was expected)
# Instead I must do something like this...
new.a = 10:12
for(i in seq_along(x)) x[[i]]$a = new.a[i]
Is there a simpler or faster alternative to using a loop?
One option would be to first unlist the list x, then replace the values named "a", and then relist the new list u based on the list structure of x.
u <- unlist(x)
u[names(u) == "a"] <- 10:12
relist(u, x)
vapply is a special case of sapply where you need to pre-specify the return type.
If you a multivariate version of sapply, the function you are looking for is mapply (or Map which is a wrapper with SIMPLIFY=FALSE`)
In general, functions with side-effects are frowned upon in R. The standard approach would be to create a new object when modifying.
You could use modlifyList to perform the modifications
xnew <- Map(modifyList, x, val = lapply(10:12,function(x) list(a = x)))
This is one of those "there has to be a function for this" questions. It's not that big a deal, but it's just annoying enough that every time I rename an object I wonder if there's a better way.
Suppose I capitalize an object that I've created and realize I'd rather have it uncapitalized:
# Create test data
X <- runif(100)
# Rename the object
x <- X
rm(X)
Is there a one-command way of doing this (that also avoids the re-copy for memory/speed reasons)? There are a few commands named rename in various packages but they all work on elements within a list, rather than on the list (or other object) itself.
I don't know of a built in way to do this but you could easily write your own function to do something along these lines. For instance this does just that without any checking to make sure the object exists or whether or not there is already an object named what you want to rename to.
mv <- function(x, y){
x_name <- deparse(substitute(x))
y_name <- deparse(substitute(y))
assign(y_name, x, pos = 1)
rm(list = x_name, pos = 1)
invisible()
}
Some example use
> x <- 3
> x
[1] 3
> y
Error: object 'y' not found
> mv(x, y)
> x
Error: object 'x' not found
> y
[1] 3
Edit: For those that didn't follow the link in the comments here is a version written by Rolf Turner that does some checking to make sure the object we want to move actually exists and asks us if we want to overwrite an existing object if the new name already has an object in it.
mv <- function (a, b) {
anm <- deparse(substitute(a))
bnm <- deparse(substitute(b))
if (!exists(anm,where=1,inherits=FALSE))
stop(paste(anm, "does not exist.\n"))
if (exists(bnm,where=1,inherits=FALSE)) {
ans <- readline(paste("Overwrite ", bnm, "? (y/n) ", sep = ""))
if (ans != "y")
return(invisible())
}
assign(bnm, a, pos = 1)
rm(list = anm, pos = 1)
invisible()
}
I have loaded in a R console different type of objects.
I can remove them all using
rm(list=ls())
or remove only the functions (but not the variables) using
rm(list=lsf.str())
My question is:
is there a way to remove all variables except the functions
Here's a one-liner that removes all objects except for functions:
rm(list = setdiff(ls(), lsf.str()))
It uses setdiff to find the subset of objects in the global environment (as returned by ls()) that don't have mode function (as returned by lsf.str())
The posted setdiff answer is nice. I just thought I'd post this related function I wrote a while back. Its usefulness is up to the reader :-).
lstype<-function(type='closure'){
inlist<-ls(.GlobalEnv)
if (type=='function') type <-'closure'
typelist<-sapply(sapply(inlist,get),typeof)
return(names(typelist[typelist==type]))
}
You can use the following command to clear out ALL variables. Be careful because it you cannot get your variables back.
rm(list=ls(all=TRUE))
Here's a pretty convenient function I picked up somewhere and adjusted a little. Might be nice to keep in the directory.
list.objects <- function(env = .GlobalEnv)
{
if(!is.environment(env)){
env <- deparse(substitute(env))
stop(sprintf('"%s" must be an environment', env))
}
obj.type <- function(x) class(get(x, envir = env))
foo <- sapply(ls(envir = env), obj.type)
object.name <- names(foo)
names(foo) <- seq(length(foo))
dd <- data.frame(CLASS = foo, OBJECT = object.name,
stringsAsFactors = FALSE)
dd[order(dd$CLASS),]
}
> x <- 1:5
> d <- data.frame(x)
> list.objects()
# CLASS OBJECT
# 1 data.frame d
# 2 function list.objects
# 3 integer x
> list.objects(env = x)
# Error in list.objects(env = x) : "x" must be an environment
I wrote this to remove all objects apart from functions from the current environment (Programming language used is R with IDE R-Studio):
remove_list=c() # create a vector
for(i in 1:NROW(ls())){ # repeat over all objects in environment
if(class(get(ls()[i]))!="function"){ # if object is *not* a function
remove_list=c(remove_list,ls()[i]) # ..add to vector remove_list
}
}
rm(list=remove_list) # remove all objects named in remove_list
Notes-
The argument "list" in rm(list=) must be a character vector.
The name of an object in position i of the current environment is returned from ls()[i] and the object itself from get(ls()[i]). Therefore the class of an object is returned from class(get(ls()[i]))