0

I have put objects that I would like to edit in a list. Say, the names of the objects are kind of like this:

name1_X
name1_Y
name2_X
name2_Y

And there are different sets of these objects, that are stored in different lists, so for each different set, they would have a slightly different name, like:

name1_P_X
name1_F1_X
name2_F2_Y

and so on.. So for every "name" there are six objects. There are two each ending with X or Y for P, F1, F2. We have three lists (listbF_P, listbF_F1, listbF_F2), each containing objects that end with X and Y.

I edited the objects in the list like this (example for only one list):

for (i in 1:NROW(listbF_P)){
  listbF_P[[i]]@first.year <- 1986
  listbF_P[[i]]@last.year <- 2005
  listbF_P[[i]]@year.aggregate.method <- "mean"
  listbF_P[[i]]@id <- makeFieldID(listbF_P[[i]])
}

When I check whether the changes were successfully applied, it works but only when referring to the objects inside the list but not the same objects "unlisted".

So if I call

listbF_P[[1]]@last.year

it returns

"2005"

But if I call

name1_X@last.year

it returns

"Inf"

The problem with this is that I want the edited objects in a different list later. So I need either a way that the latter call example returns "2005" or a way that I can search for a certain object name pattern in multiple lists to put the ones that fit the pattern into another list. This is because the example above was made with multiple lists (listbF_P, listbF_F1, listbF_F2) and these lists contain a pattern matching "X" and another matching "Y". So basically I want to have two lists with edited objects, one matching pattern "X" and the other matching pattern "Y".

I would call the list matching the desired patterns like this:

listbF_ALL_X <- mget(ls(pattern=".*_X$"))
listbF_ALL_Y <- mget(ls(pattern=".*_Y$"))

The first list would hence contain all objects ending with "X", e.g.:

name1_P_X
name1_F1_X
name1_F2_X
name2_P_X
[...]

and I would like to have the ones that I edited in the loop earlier

..but when calling the objects out of that list

listbF_ALL_X[[1]]@last.year

again just returns

"Inf"

since it takes the objects out of the environment and not the list. But I want it to return the desired number that has been changed (e.g. "2005").

I hope my problem and the two possible ways of solving them are clear.. If something isn't, ask :)

Thanks for any input

Regards

Ferdi
  • 81
  • 7
  • It's easier to help you if you include a simple [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) with sample input and desired output that can be used to test and verify possible solutions. – MrFlick Sep 03 '20 at 19:29
  • Hello, thanks for the information! I added sample input and output. Hope it helps. – Ferdi Sep 04 '20 at 08:20

2 Answers2

0

In R, unlike in many other modern languages, (almost) all objects are logically copies of each other. You can’t have multiple names that are references to the same object (see below for caveats).

But even if this was supported, your design looks confusing. Rather than have lots of related objects with different names, put your objects into nested lists and classes that logically relate them. That is, rather than have objects with names name{1..10}_{P,F1,F2}_{X,Y}, you should have one list, name, in which you store nested lists or classes with named members P, F1, F2 which, in turn, are objects that have names X and Y. Then you could access an object by, say, name[1L]$P$X (or name[1L]@P@X, if you’re using S4 objects with slots).

Or you use a more data-oriented approach and flatten all these nested objects into a table with corresponding columns P, F1, F2, X and Y. Which solution is more appropriate depends on your exact use-case.


Now for the caveat: you can use reference semantics in R by using *environments8 instead of regular objects. When copying an environment, a reference to the same environment object is created. However, this semantic is usually confusing because it’s contrary to the expectation in R, so it should be used with care. The ‘R6’ package creates an object system with reference semantics based on environments. For many purposes where reference semantics are indispensable, ‘R6’ is the right answer.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • So far my design worked just fine, I felt that nested lists would be more confusing so I did not do that.. but maybe I should. But also good to know that I have another option available with R6. Thanks for your elaborate answer! – Ferdi Sep 07 '20 at 14:12
0

I found another solution: I went on by modifying this part:

listbF_ALL_X <- mget(ls(pattern=".*_X$"))
listbF_ALL_Y <- mget(ls(pattern=".*_Y$"))

To not call objects from the environment but by calling objects from each list:

listbF_ALL_X <- c(c(listbF_P, listbF_F1, listbF_F2)[grepl(".*_X$", names(c(listbF_P, listbF_F1, listbF_F2)))])
listbF_ALL_Y <- c(c(listbF_P, listbF_F1, listbF_F2)[grepl(".*_Y$", names(c(listbF_P, listbF_F1, listbF_F2)))])

It's not the prettiest way of doing it but it works and in my case it was the solution that required the least amount of change in my script.

Ferdi
  • 81
  • 7