-1

In a previous Using R, how to reference variable variables (or variables variable) a la PHP[post]

I asked a question about something in R analagous to PHP $$ function:

Using R stats, I want to access a variable variable scenario similar to PHP double-dollar-sign technique: http://php.net/manual/en/language.variables.variable.php

Specifically, I am looking for a function in R that is equivalent to $$ in PHP.

The get( response works for strings (characters).

lapply is a way to loop over lists

Or I can loop over and get the values ...

for(name in names(vars))
            {
            val = vars[[name]];

I still haven't had the $$ function in R answered, although the lapply solved what I needed in the moment.

`$$` <- function

that allows any variable type to be evaluated. That is still the question.


UPDATES


> mlist = list('four'="score", 'seven'="years");
> str = 'mlist$four'
> mlist
$four
[1] "score"

$seven
[1] "years"

> str
[1] "mlist$four"
> get(str)
Error in get(str) : object 'mlist$four' not found
> mlist$four
[1] "score"

Or how about attributes for an object such as mobj@index


UPDATES #2

So let's put specific context on the need. I was hacking the texreg package to build a custom latex output of 24 models of regression for a research paper. I am using plm fixed effects, and the default output of texreg uses dcolumns to center, which I don't like (I prefer r@{}l, so I wanted to write my own template. The purpose for me, to code this, is for me to write extensible code that I can use again and again. I can rebuild my 24 tables across 4 pages in seconds, so if the data change, or if I want to tweak the function, I immediately have a nice answer. The power of abstraction.

As I hacked this, I wanted to get more than the number of observations, but also the number of groups, which can be any user defined index. In my case it is "country" (wait for it, hence, the need for variable variables).

If I do a lookup of the structure, what I want is right there: model$model@index$country which would be nice to simply call as $$('model$model@index$country'); where I can easily build the string using paste. Nope, this is my workaround.

getIndexCount = function(model,key="country")
    {
    myA = attr(summary(model)$model,"index");
    for(i in 1:length(colnames(myA)))
        {
        if(colnames(myA)[i] == key) {idx = i; break;}
        }
    if(!is.na(idx))
        {
        length(unique(myA[,idx]));
        } else { 
            FALSE;
            }
    }


UPDATES #3

Using R, on the command line, I can type in a string and it gets evaluated. Why can't that internal function be directly accessed, and the element captured that then gets printed to the screen?

6
  • 1
    I'm at a bit of a loss as to what you're really after, except to say that if your code depends this heavily on evaluating arbitrary text as language objects, that's usually a good sign that your whole approach is wrong. While what you describe may be common in PHP, it is not in R. Indeed it is rare enough that people generally recommend against it entirely. There's almost always a better way. Commented Feb 8, 2016 at 21:43
  • I have been coding in PHP for 15 years, R for 10 years... and at times, it would be better to be able to just directly access elements of an object (in both languages). Someone once said that R is about objects and functions, where is the function to access the objects ... in an albeit crude manner. Sometimes I just what mlist$four or lm@index$country and I don't want or need to setup an entire lapply routine Commented Feb 8, 2016 at 22:46
  • "Objects" in R means something different than "objects" in object-oriented languages like PHP. They're different in R. The closest R equivalent are S4 objects, which manage to emulate dereferencing in some contexts via "slots" and the @ operator, but they need to be specifically created as S4 objects for them to work this way. It's not a general feature of the language. Commented Feb 8, 2016 at 22:50
  • The someone "once said" is a bit flippant, tongue-in-cheek. It is the attributed to the creator of S, who is also involved with R dev, Chambers. Commented Feb 8, 2016 at 22:54
  • <shrug> I simply cannot tell from what you have written in this question or the previous one why R's existing capabilities (named lists, get, etc) are not sufficient, except that you seem to be insisting on something that behaves precisely like a feature of a different language, rather than simply using R's features for achieving the same result, albeit somewhat differently. Commented Feb 8, 2016 at 22:59

2 Answers 2

0

There is no equivalent function in R. get() works for all types, not just strings.

Sign up to request clarification or add additional context in comments.

7 Comments

It does not work for all types. See updates on my post.
Types and subsetting based on variable names are not the same thing. str = 'mlist'; get(str); works just fine on type list.
I'm aware you can do it in PHP. R is not actually an object-oriented language. It simulates some such behaviour in various ways. Dereferencing dynamically in the manner you show is not part of R's syntax. There are other ways to access subsets of R data structures. Or, you can write custom functions to do what you want.
Well why are you telling me types and subsetting is not the same thing. I can do it in PHP and am asking if it can be done in R. Can it?
As mentioned in my answer, no, it cannot be done the way you want in R. I told you types and subsetting are not the same thing because you stated that get() doesn't work on all types, which it does. It doesn't emulate the subsetting that you want.
|
0

Here is what I came up with, after chatting with the R-bug group, and getting some ideas from them. KUDOS!

`$$` <- function(str)
    {
    E = unlist( strsplit(as.character(str),"[@]") );
        k = length(E);
        if(k==1)
            {
            eval(parse(text=str));
            } else {
                # k = 2
                nstr = paste("attributes(",E[1],")",sep="");
                nstr = paste(nstr,'$',E[2],sep="");

                if(k>2) {
                    for(i in 3:k)
                        {
                        nstr = paste("attributes(",nstr,")",sep="");
                        nstr = paste(nstr,'$',E[i],sep="");
                        }
                    }
                `$$`(nstr);
                }
    }

Below are some example use cases, where I can directly access what the str(obj) is providing... Extending the utility of the '$' operator by also allowing '@' for attributes.

model = list("four" = "score", "seven"="years");
str = 'model$four';
result = `$$`(str);
print(result);

matrix = matrix(rnorm(1000), ncol=25);
str='matrix[1:5,8:10]';
result = `$$`(str);
print(result);



## Annette Dobson (1990) "An Introduction to Generalized Linear Models".
## Page 9: Plant Weight Data.
ctl <- c(4.17,5.58,5.18,6.11,4.50,4.61,5.17,4.53,5.33,5.14);
trt <- c(4.81,4.17,4.41,3.59,5.87,3.83,6.03,4.89,4.32,4.69);
group <- gl(2, 10, 20, labels = c("Ctl","Trt"));
weight <- c(ctl, trt);
lm.D9 <- lm(weight ~ group);
lm.D90 <- lm(weight ~ group - 1); # omitting intercept

myA = anova(lm.D9); myA; str(myA);

str = 'myA@heading';
result = `$$`(str);
print(result);


myS = summary(lm.D90); myS; str(myS);


str = 'myS$terms@factors';
result = `$$`(str);
print(result);

str = 'myS$terms@factors@dimnames';
result = `$$`(str);
print(result);

str = 'myS$terms@dataClasses@names';
result = `$$`(str);
print(result);

After realizing the back-tick can be a bit tedious, I chose to update the function, calling it access

access <- function(str)
    {
    E = unlist( strsplit(as.character(str),"[@]") );
        k = length(E);
        if(k==1)
            {
            eval(parse(text=str));
            } else {
                # k = 2
                nstr = paste("attributes(",E[1],")",sep="");
                nstr = paste(nstr,'$',E[2],sep="");

                if(k>2) {
                    for(i in 3:k)
                        {
                        nstr = paste("attributes(",nstr,")",sep="");
                        nstr = paste(nstr,'$',E[i],sep="");
                        }
                    }
                access(nstr);
                }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.