I would like to replace the first value in each list element with the second value from the same element.
For example I would like a function to transform lst into lst2
lst<-list(c(0:4),c(5:9))
lst
lst2<-list(c(1, c(1:4)),c(6,c(6:9)))
lst2
I know that I can do
lst[[1]][1]=lst[[1]][2]
lst[[2]][1]=lst[[2]][2]
But I would like a function to iterate over all list elements. I have tried various things (all unsuccessful) with lapply such as:
lapply(list, function(x) x[1]=x[2])
We can use lapply to loop over the list and we need to return the x if we are using anonymous function call.
lstN <- lapply(lst, function(x) {x[1] <- x[2]
x})
identical(lst2, lstN)
#[1] TRUE
Related
data =data.frame(sapply(data,function(x) ifelse((x==999),NA,x)))
Could you explain how function(x)....,x works? I know what input and output of this function are, it just replaces 999 values with NAs in dataframe, but I want to know how this function(x) works in General.
This is your function with the name my_func: It takes a value x checks if it is 999, if not it gives back the value of x, if yes it gives back 999:
my_func <- function(x) {
ifelse(x==999, NA, x)
}
You now can use this function as follows:
named function standalone:
my_func(mtcars$mpg)
As named function with lapply or sapply ...
Basically sapply function in R does the same job as lapply() function but returns a vector:
lapply(X, FUN)
Arguments:
-X: A vector or an object
-FUN: Function applied to each element of x
lapply(mtcars$mpg, my_func)
sapply(X, FUN)
Arguments:
-X: A vector or an object
-FUN: Function applied to each element of x
sapply(mtcars$mpg, my_func)
Now your question:
You can use a function in this case my_func directly without defining or naming first as an anonymous function (means the function has not a name) like:
lapply(mtcars$mpg, function(x) ifelse(x==999, NA, x))
Note: essentially after function(x) it is the body part of your named function my_func.
If I have a list with some attribute, and I apply a function to all elements of that list, the attribute gets removed.
# Define list and attribute
my_list <- list(1,2,3)
attr(my_list, "my_attribute") <- "foo"
# Function that I will apply over list elements
add_1 <- function (x) {
return(x + 1)
}
my_list <- lapply(my_list, add_1)
# Attribute is lost
attributes(my_list)
#> NULL
How can I keep the list attributes after lapply?
Well I guess I could just store the attributes before the lapply call
# Define list and attribute
...
# Function that I will apply over list elements
...
stored_attributes <- attributes(my_list)
my_list <- lapply(my_list, add_1)
attributes(my_list) <- stored_attributes
... still, I don't really understand this behaviour
A way to retain the attributes is with [] -
my_list[] <- lapply(my_list, add_1)
attributes(my_list)
#$my_attribute
#[1] "foo"
I want to make a table with all the dim() of objects in the environment. ls() returns a list of characters which lapply will not take as object names and operate properly on. What to do? Using R.
> lapply(ls(), dim)
just returns
[[1]]
NULL
You may use parse and eval to change the string vector to env objects and then use dim.
lapply(ls(), function(x) dim(eval(parse(text=x))))
1) Use eapply and then optionally use Filter to remove components with no dim. This creates a named list with the dimensions in the corresponding components.
Filter(length, eapply(.GlobalEnv, dim))
2) A variation would be to create a matrix result such that the row names are the variable names.
do.call("rbind", eapply(.GlobalEnv, dim))
3) or to restrict the output to data frames and not arrays (as arrays might cause problems if there are arrays not of two dimensions) then:
df_dim <- function(x) if (is.data.frame(x)) dim(x)
do.call("rbind", eapply(.GlobalEnv, df_dim))
4) or to restrict it to objects having 2 dimensions including both data frames and arrays:
two_dim <- function(x, dimx = dim(x)) if (length(dimx) == 2) dimx
do.call("rbind", eapply(.GlobalEnv, two_dim))
or
do.call("rbind", Filter(function(x) length(x) == 2, eapply(.GlobalEnv, dim)))
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
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)))