I often struggle with understanding how to assign values in R
within loops. The desired behavior seems simple to me, but I clearly don't have a good grasp on the subtleties of evaluation and assignment in R
.
For example, I've got a bunch of data objects that I want to add a comment to each object (they are unrelated and so using them together in a list beyond this assignment does not make sense). Here's a MWE
my_comment <- paste0("these objects were created on ", date())
obj1 <- "content1"
obj2 <- "content2"
obj_l <- list(obj1, obj2)
for(obj in obj_l) {
comment(obj) <- my_comment
}
## get 'NULL', but want "these objects were created ..."
comment(obj1)
## get 'NULL'
comment(obj_l)
## assignment is only made to temp variable 'obj'
## This makes sense, but not the desired outcome.
comment(obj)
I imagine the solution will look something like the following pseudo code
obj_l <- c("obj1", "obj2")
for(name in obj_l)
unknown_function(name, comment, my_comment, unknown_args)
}
or
modify(obj_l, my_comment, unknown_syntax)
If my pseudo code is on track, can someone help me with the unknown_
parts?
CodePudding user response:
Any of these work to comment the components of obj_l
or in the case of #3 to produce a new list with comments added. We show that the object has been changed for #1 but the others are the same.
# 1
obj1 <- "content1"
obj2 <- "content2"
obj_l <- list(obj1, obj2)
for(i in seq_along(obj_l)) {
comment(obj_l[[i]]) <- "some comment"
}
dput(obj_l)
## list(structure("content1", comment = "some comment"),
## structure("content2", comment = "some comment"))
# 2
obj1 <- "content1"
obj2 <- "content2"
obj_l <- mget(c("obj1", "obj2"))
for(nm in names(obj_l)) {
comment(obj_l[[nm]]) <- "some comment"
}
# 3
obj1 <- "content1"
obj2 <- "content2"
obj_l <- list(obj1, obj2)
obj_2 <- lapply(obj_l, `comment<-`, "some comment")
If what you wanted was to comment obj1
and obj2
then
# 4
obj1 <- "content1"
obj2 <- "content2"
nms <- c("obj1", "obj2")
e <- .GlobalEnv # environment with objects
for(nm in nms) comment(e[[nm]]) <- "some comment"
# 5
obj1 <- "content1"
obj2 <- "content2"
obj_l <- mget(c("obj1", "obj2")) # named list w obj1, obj2 elements
lapply(obj_l, `comment<-`, "some comment") |> list2env(.GlobalEnv)
CodePudding user response:
With lists in a loop, it's usually easier to loop over the indexes or the names, not the actual objects:
for(i in seq_along(obj_l)) {
comment(obj_l[[i]]) <- my_comment
}
comment(obj_l[[i]])
# [1] "these objects were created on Wed Nov 9 10:55:27 2022"
And you have added a comment to the item in the list, don't expect obj1
to have a comment. (Better not to think about obj1
at all, what you have is obj_l
which has 2 elements, obj_l[[1]]
and obj_l[[2]]
.
CodePudding user response:
After some more reading of help pages and trial and error, here's my solution
obj1 <- "content1"
obj2 <- "content2"
obj_l <- c("obj1", "obj2")
comment <- '"my comment!"'
for(x in obj_l) {
my_exp <- paste0("comment(", x, ") <- ", comment)
parse(text = my_exp)
}
comment(obj1)
# [1] "my comment"
CodePudding user response:
My attempt at answering the actual question without using the comment()
function.
See Below:
create_comment <- function(object, comment) {
new_object <- list(Object = object, Comment = comment)
return(new_object)
}
test <- map(c(obj1, obj2), create_comment, comment = my_comment)
Instead of using the comment()
function I built a function that creates a named list object for each individual object. This makes it so that I can create a large list with all of my stored objects and it also stores the character string my_comment
within the list.
the output from test shows...
[[1]]
[[1]]$Object
[1] "content1"
[[1]]$Comment
[1] "these objects were created on Wed Nov 09 16:04:04 2022"
[[2]]
[[2]]$Object
[1] "content2"
[[2]]$Comment
[1] "these objects were created on Wed Nov 09 16:04:04 2022"
I can then use [[i]]
to access my objects
For example:
test[[1]]
$Object
[1] "content1"
$Comment
[1] "these objects were created on Wed Nov 09 16:04:04 2022"
And I can further access my individual comments or object by using the $
test[[1]]$Comment
[1] "these objects were created on Wed Nov 09 16:04:04 2022"