2

I have a problem in R and it is the following: How can you assign a value to an element and then later recall an element in who's name you refer to the previously defined element.

Thus you define an element x

i <- value

Later you use x.i where "i" should be its value.

This is a problem in the following two cases:

1) First you create 10 elements with the name x.1 till x.10

for(i in 1:10){
        assign(paste0("X.", i), 1:3)
}

Then you want to change the name of the elements in x.1 till x.10

for(i in 1:10){
        assign(names(paste0("X.", i)), c("foo","bar","norf"))
}

This does not work.

2) I want to define two values:

year <- 1
code <- 2

And then in a dataframe "Data.year" (="Data.1") only those observations where the colum "code" is equal to the value of the previously defined "code" (=2) should be stored. With the name format: "Data.year.code" (=Data.1.2)

assign(paste0("Data.", i, code, sep="."), as.name(paste("Data",year , sep="."))[as.name(paste("Data",y , sep="."))$code==code,])

Here I tried to use as.name function in but this does not work. The problem is that R can obviously not reconise that "year" and "code" in the expression "Data.year.code" have a value. In stata you solve this by using `, But I do not now how you do this in R. Normally I just google something when I do not know the answer. But I have no idea how I should name this problem and thus can't find it...

It should have an easy and straightforward solution.

Jan-Pieter
  • 111
  • 1
  • 9
  • So essentially what you need is to be able to call a variable by string? – LyzandeR Jan 20 '15 at 10:52
  • Don't assign to the global environment like that. Collect these objects in a `list` or a different `environment`. That will make the whole task (at least what I understood of it) easier, tidier and possibly safer. – Roland Jan 20 '15 at 10:58
  • @LyzandeR: I don't think that that is what I want to do. Or maybe I do not fully understand what you mean. In the case of `names(paste0("X.", i))' R reads a string "X.(value of i)" while I want it to recognize "X.(value of i)" as an element with a value. So that I use Paste is not correct but I do not know how to do it in a different way. – Jan-Pieter Jan 20 '15 at 11:07
  • So essentially you need exactly what I 'm saying :P. `paste0('X',i)` will return a string and therefore `names()` won't be able to recognise it (because it is a string and not a variable which you would like). – LyzandeR Jan 20 '15 at 11:09
  • @Roland: Is using lists the only option. Because in the end I would like to define a large number of data frames and I would prefer not to store them in lists. – Jan-Pieter Jan 20 '15 at 11:11
  • I like Akrun's way below but if it seems overly complicated to use `names<-()` which is actually the `names()` assignment function, you can also have a look at this post: http://stackoverflow.com/questions/1743698/r-eval-expression – LyzandeR Jan 20 '15 at 11:13
  • Thank you all for your responds! @LyzandeR: I assume you refer to using `parse(text="string")` but how does this help me in my case? – Jan-Pieter Jan 20 '15 at 12:48
  • 1
    There's no logical reason to create a large number of data frames and not store them in a list. A list of data frames is simply a [large] number of data frames with a little organisation applied. Its a good thing. – Spacedman Jan 20 '15 at 14:04
  • Probably you guys are right that I should store them in a list! – Jan-Pieter Jan 20 '15 at 14:46

2 Answers2

1

Based on your code with assign, an option is (but as @Roland mentioned in the comments, it would be easier and safer to work with a "list")

for(i in 1:10){
 assign(paste0('X.',i), `names<-`(get(paste0('X.', i)), 
        c('foo', 'bar', 'norf')))
 }

X.1
#foo  bar norf 
#  1    2    3 
X.2
# foo  bar norf 
#  1    2    3 

Or you can try it in a list

 lst <- lapply(mget(paste0('X.',1:10)), function(x) {
                names(x) <- c('foo', 'bar', 'norf')
              x})

If you need to change the original variables to reflect the changes

 list2env(lst, envir=.GlobalEnv)

Update

If you need to change the values in the vector, it is easier

 list2env(lapply(mget(paste0('X.', 1:10)), 
   function(x) x <- c('foo', 'bar', 'norf')), envir=.GlobalEnv)

 X.1
#[1] "foo"  "bar"  "norf"

Or just

 for(i in 1:10){
   assign(paste0('X.', i), c('foo', 'bar', 'norf'))
  }
akrun
  • 874,273
  • 37
  • 540
  • 662
  • Thank you very much for your responds! However I thought this solved it but now I tried to apply this solution to the second problem I mentioned in my question and there it does not work. The first problem I created to give a simpler example of what is in fact the same problem. Or is using `\`names<-\`` a general way of solving this and do I just not understand it? – Jan-Pieter Jan 20 '15 at 13:04
  • @Jan-Pieter Do you want to change the elements in each of the vectors as Lyzander showed. I thought you want the names to be changed as in the question. – akrun Jan 20 '15 at 14:17
  • In my question I tried to give two examples of the same problem. The names changing problem was just the first example. In the second case I wanted to change the vector multiple times in the same line. Sorry if I was not clear, maybe by giving multiple examples I made it just confusing. Thanks anyway! – Jan-Pieter Jan 20 '15 at 14:39
  • @akrun He wanted the names Akrun in the first example you are right. I think it is the methodology that worked for Jan in the end in his actual problem. – LyzandeR Jan 20 '15 at 14:40
  • @LyzandeR Thanks, I was curious. Jan-Pieter, Sorry didn't read the second part thoroughly – akrun Jan 20 '15 at 14:42
0

The idea (although I need to tell you that it is a bit frowned upon by the R community) is to make a 'big' string in the loop which will be evaluated afterwards:

This works as you say:

 for(i in 1:10){
  assign(paste0("X.", i), 1:3)
}

and so in order to change the names you do the following:

for(i in 1:10){
   eval(parse(text=sprintf('X.%s <- c("foo","bar","norf")',i)))
}

Output:

> X.1
[1] "foo"  "bar"  "norf"
> X.2
[1] "foo"  "bar"  "norf"

So you make the big string with sprintf in this occasion:

> cat(sprintf('X.%s <- c("foo","bar","norf")',i)) #cat is used for demonstration here
X.1 <- c("foo","bar","norf") #this is the string for i==1 for example

and then you convert it to an expression with parse and then you evaluate the expression with eval.

As I said previously it is not the best technique to use but to be honest it has helped me quite a few times.

LyzandeR
  • 37,047
  • 12
  • 77
  • 87
  • @Akrun sorry . Which first assign do you mean? – LyzandeR Jan 20 '15 at 14:34
  • This is indeed the kind of solution I was looking for! This works in all cases. – Jan-Pieter Jan 20 '15 at 14:34
  • @LyzandeR I may have missed some key points. Anyway, I was referring to the one in my Update. – akrun Jan 20 '15 at 14:35
  • @akrun Yeah I was the first one in the comments to say that I like your way and that it works great. I also support the opinion that making a list is the best solution. I just wanted to show an alternative of how it can work with a string and `eval(parse...))` – LyzandeR Jan 20 '15 at 14:38
  • @LyzandeR Thanks for that. I was trying to understand the difference in techniques. Not in a bad way :-) – akrun Jan 20 '15 at 15:13
  • @akrun I know akrun thanks. I never thought you downvoted. I upvoted yours as you know. You always mean well I know that :) – LyzandeR Jan 20 '15 at 18:21