Loss of attributes with lapply (R) - r

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"

Related

Update first value in each list element in R

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

Loop over list of functions, and return function name as character

In R, I have a list of functions (strategies for a simulation). For example:
a <- function(x){
return(x)
}
b <- function(y){
return(y)
}
funclist <- list(a,b)
I'd like to write some code that returns the name of each function. Normally, for functions I would use:
as.character(substitute(a))
But this does not work for the list, as it just would return the list name (as expected). I then tried lapply:
> lapply(X = funclist,FUN = substitute)
Error in lapply(X = funclist, FUN = substitute) :
'...' used in an incorrect context
But get the above error.
Ideally I would get (lapply solution):
[[1]]
[1] "a"
[[2]]
[1] "b"
or even (sapply solution):
[1] "a" "b"
After you do
funclist <- list(a,b)
The parameters a and b are evaluated and the functions they point to are returned. There is no way to get back to the original names. (The substitute() "trick" works on parameters passed to functions as promises. It will not work on evaluated called without additional escaping.)
If you want to retain names, it's best to use a named list. You can do
funclist <- list(a=a,a=b)
or
funclist <- setNames(list(a,b), c("a","b"))
or even use mget() here
funclist <- mget(c("a","b"))
All these methods will returned a named list and you can use
names(funclist)
# [1] "a" "b"
to get the names

How to make the elements of a matrix callable functions

I want to make a matrix of functions (that I wrote). Then access them element wise and call.
So I have : func1(x) , func2(y), func3(z) and func4(t) that are four R functions I wrote that work fine.They return numerics.
Now if I do:
a_matrix <- matrix(c(a=func1,b=func2,c=func3,d=func4),2,2)
a_func<-a_matrix[1,1]
a_func(x)
I get the following error:
error:attempt to call non-function.
Instead of matrix if I use list,
a_list<-list(a=func1,b=func2,c=func3,d=func4)
a_func<-list$a
a_func(x)
gives expected result
typeof(list$a)
[1] "closure"
If I do :
typeof(a_matrix)
[1] "list"
typeof(a_matrix[1,1])
[1] "list"
(am using R 3.1.1)
When you create non-atomic matrices like that, they are basically made into fancy lists. Similar rules apply to these lists as to regular lists when it comes to indexing; namely that [ ] will always return another list, and [[ ]] will extract the element without the list wrapper. You really want
func1 <- function(x) x+1
func2 <- function(x) x+2
func3 <- function(x) x+3
func4 <- function(x) x+4
a_matrix <- matrix(c(a=func1,b=func2,c=func3,d=func4),2,2)
a_func <- a_matrix[[1,1]]
a_func(5)
# [1] 6
You'd get the same results with your standard list syntax if you did
a_list <- list(a=func1,b=func2,c=func3,d=func4)
a_func <- a_list["a"]
a_func(5)
# Error: could not find function "a_func"
a_func <- a_list[["a"]]
a_func(5)
# [1] 6

Create an ellipsis (...) from list

Is it possible to create a ellipsis (...) from a list? The idea is to be able to do something like:
mylist <- list(a=1,b=2,c=3)
myellipsis <- create_ellipsis(mylist)
print(switch('a', myellipsis)) # output 1
You want do.call, which can pass the content of a list to a functions ... argument:
do.call(function(...) print(switch('a', ...)), mylist)

Recursively editing a list in R

In my program, I am recursively going over a nested list and adding elements to an overall list that I will return. There are a few details to be taken care of, so I can't just use unlist.
formulaPart is taken to be a formula object.
My code is:
parseVariables <- function(formulaPart, myList){
for(currentVar in as.list(formulaPart))
if(typeof(currentVar == 'language'
parseVariables(currentVar, myList)
else
if(! toString(currentVar) %in% c(\\various characters)
list <- c(list, currentVar)
}
I have checked that the function correctly adds elements to the list when it should. The problem is that the list loses elements due to recursion. The elements added during one inner recursive call are not saved for another recursive call.
If this was in C++, I could just use a pointer; the same for Java. However, I do not understand how to handle this error in R.
R does something like pass-by-value, so you can't modify (most) existing objects just by passing them into a function. If you want to add on to something recursively, one trick would be to use an environment instead, which get passed by reference. This can easily be coerced to list when you're done.
parseVariables <- function(formulaPart, myList){
for(currentVar in as.list(formulaPart)) {
if(typeof(currentVar) == 'language') {
parseVariables(currentVar, myList)
}
else {
if(! toString(currentVar) %in% c(':', '+', '~'))
assign(toString(currentVar), currentVar, myList)
}
}
}
f1 <- z ~ a:b + x
f2 <- z ~ x + y
myList <- new.env()
parseVariables(f1, myList)
parseVariables(f2, mylist)
ls(myList)
# [1] "a" "b" "x" "z"
as.list(myList)
# $x
# x
#
# $z
# z
#
# $a
# a
#
# $b
# b

Resources