-1

How can I select the second column of a dynamically named variable?

I create variables of the form "population.USA", "population.Mexico", "population.Canada". Each variable has a column for the year, and another column for the population value. I would like to select the second column from each of these variables during a loop.

I use this syntax:

sprintf("population.%s", country)[, 2]

R returns the error: Error in sprintf("population.%s", country)[, 2] : incorrect number of dimensions

Gavin Simpson
  • 170,508
  • 25
  • 396
  • 453
Don P
  • 60,113
  • 114
  • 300
  • 432
  • 1
    See Gavin's answer, but you can tell your example wont work by looking at what `sprintf('population.%s', country)` returns. – Justin Aug 04 '12 at 21:37
  • I'm still learning how to interpret R's output. I didn't realize that the output was telling me it's a string. Maybe it was just displaying the variable name as a string? Or even if it did return a string, I'm used to languages (PHP) where that is enough to get the value. – Don P Aug 04 '12 at 22:38

2 Answers2

11

Based on your sequence of questions over the last few minutes, I have two general recommendations for you as you get familiar with R:

  1. Don't use sprintf.
  2. Don't use assign.

Now, obviously, those functions are both useful at times. But you've learned about them too early, before you've mastered some basic stuff about R's data structures. Try to write code without those crutches (for the time being!), as they're just causing you problems.

Rather than creating separate individual variables for each nation's population, place them in a list.

population <- vector("list",3)
names(population) <- c('USA','Mexico','Russia')

Then you can access each using the string representation of the name of each country:

population[['USA']] <- 10000

Or,

region <- 'USA'
population[[region]]

In this example, I've assigned a single value to a list element, lists will hold any other data type, including matrices or data frames. It will be a lot less typing than using sprintf and assign, and a lot safer and more efficient as well.

joran
  • 169,992
  • 32
  • 429
  • 468
  • Thanks for all the help today Joran - it is clear to me that I'm missing the fundamentals of structuring and working with a dataset in R. Do you know a good resource for learning these? I've gone through many 'tutorials' and introductions to using R and time-series in R, but unfortunately they don't seem to teach the fundamentals in a way that let's me use it as flexibly as any other language. – Don P Aug 04 '12 at 22:34
  • Also regarding the use of sprintf, I don't know any alternative for passing values when I am using a loop. – Don P Aug 04 '12 at 22:36
  • @DonnyP The alternative is to not pass values into a loop (or `paste`)! Instead use things like named lists and R's list functions. like `[`, `[[` and the `apply` family. – Justin Aug 04 '12 at 22:44
  • @DonnyP I should clarify that using `sprintf` for constructing your db queries is totally fine. It was the combination of `sprintf` and `assign` to make individual variables that I was talking about. – joran Aug 05 '12 at 03:26
  • @DonnyP As for your other questions, the best advice I can offer is to keep asking questions, but make sure that you come up with examples for your questions that are [completely reproducible](http://stackoverflow.com/q/5963269/324364). That way the answers you get will show you directly how to use more R-like constructs. – joran Aug 05 '12 at 03:32
6

See ?get. Here is an example:

> country <- "FOO"
> assign(sprintf("population.%s", country), data.frame(runif(5), runif(5)))
> 
> get(sprintf("population.%s", country))[,2]
[1] 0.2241105 0.5640709 0.5945869 0.1830719 0.1895938

It is critically important to look at the object returned by a function if you get an error. It is immediately clear why your example fails if you just look at what it returns:

> sprintf("population.%s", country)
[1] "population.FOO"

At that point it would be immediately clear, if you didn't already know or have thought to read ?sprintf, that sprintf() returns a string not the object of that name. Armed with that knowledge you would have narrowed down the problem to how to recall an object from the computed name?

Gavin Simpson
  • 170,508
  • 25
  • 396
  • 453
  • Thanks Gavin, I didn't realize that R wouldn't search for an object equal to the string. – Don P Aug 04 '12 at 22:39
  • @DonnyP It would be horrible if R always decided that if a string contained the name of an object that it would return the object. – Dason Aug 05 '12 at 00:35