1

I want to pass some attribute of the list as parameter of a function.

foo <- function(lst, attr) {
   # lst is a list
   # I want to transform attr into 'factor' mode.
    data$substitute(attr) <- as.factor(lst$substitute(attr))
}

This snippet is failed with error information 'attempt to apply non-function'. Actually, data$substitute(attr) failed to obtain the attr attribute of lst.

The concrete example is as following: Let us create a list named lst.

lst <- list()
lst$CLICK_DT <- c(as.Date("2015-07-01"), as.Date("2015-07-02"))
lst$CLICK <- c(111,123)

Then lst$substitute(CLICK_DT) failed to obtain the CLICK_DT attribute of lst.

foo(lst, CLICK) should transform lst$CLICK into factor mode and foo(lst,CLICK_DT) should transform lst$CLICK_DT into factor mode.

What is the easy way to do this? Thanks.

user1903382
  • 95
  • 1
  • 2
  • 11
  • 2
    Use `[` instead of `$` Please consider to provide some example to test your function – akrun Aug 05 '15 at 07:24
  • sorry, akrun. It seems not wok. The error is "invalid subscript type ''symbol' ". Actually, if `data` is a list, `data$substitute(attr)` still not work. So I think the reason is that I do not use `substitute` correctly. – user1903382 Aug 05 '15 at 07:33
  • Please provide some reproducible example for others to help you better. It was just a guess. – akrun Aug 05 '15 at 07:34
  • hi, I restated my description just now. Thanks. – user1903382 Aug 05 '15 at 07:44
  • Please also indicate how you're calling `foo()`, or how you *want* to be able to call `foo()`. Is it `foo(lst,'CLICK_DT')` or `foo(lst,CLICK_DT)`? – bgoldst Aug 05 '15 at 07:45
  • I want to call `foo()` with `foo(lst, CLICK)` or `foo(lst,CLICK_DT)`. Thanks. – user1903382 Aug 05 '15 at 07:51

2 Answers2

1

In your code, data and attr are two different variables being passed into the function - attr is not an attribute (i.e. a column) in data. So, instead just do this:

foo <- function(data, attr) {
  # Transform attr into 'factor' mode thus:
  attr <- factor(attr)
}

...and you're done (in fact, if this is all your function will be doing, you do not even need to pass in that data variable, and using just function(attr) will work just fine).

Then, if attr is supposed to be a column in your data frame, then use the $ sign when passing a variable to the function thus:

# declare the function
foo <- function(attr) {
      # Transform attr into 'factor' mode thus:
      attr <- factor(attr)
    }

# use it thus
foo(data$attr) #notice the dollar sign - you're passing one of the variables

Hope this helps!

Deolu A
  • 752
  • 1
  • 6
  • 13
1

I see you're trying to apply non-standard argument evaluation using substitute() to allow specifying the target list component using an unquoted symbol as the second argument of foo(). Here's how to do that:

foo <- function(lst,name.arg) {
    name.sym <- substitute(name.arg);
    if (typeof(name.sym) != 'symbol') stop('name must be a symbol.');
    name.str <- as.character(name.sym);
    lst[[name.str]] <- as.factor(lst[[name.str]]);
    lst;
};
lst <- list(CLICK_DT=c(as.Date('2015-07-01'),as.Date('2015-07-02')),CLICK=c(111,123));
lst;
## $CLICK_DT
## [1] "2015-07-01" "2015-07-02"
##
## $CLICK
## [1] 111 123
##
sapply(lst,class);
##  CLICK_DT     CLICK
##    "Date" "numeric"
lst <- foo(foo(lst,CLICK_DT),CLICK);
lst;
## $CLICK_DT
## [1] 2015-07-01 2015-07-02
## Levels: 2015-07-01 2015-07-02
##
## $CLICK
## [1] 111 123
## Levels: 111 123
##
sapply(lst,class);
## CLICK_DT    CLICK
## "factor" "factor"

Couple of additional points: You're misusing the word "attribute". In R, "attribute" is a well-defined term that refers to a secondary data object that is attached to another (primary) data object. You can read/write the attributes of an object using attr() and attributes(). The word you should be using here is "component", since we're talking about list components. You can also use the word "element", since lists are viewed as a kind of vector, and are even referred to as "generic vectors" in the R source.

Secondly, the dollar operator is actually a function. When you use substitute() to access the parse tree of an expression, if the expression involves the dollar operator, then the type of the return value will be 'language' (with class 'call' or '{' if surrounded by a braced block), rather than 'symbol' (class 'name'). This is also true of normal function calls, for example typeof(substitute(sum(1,2))) also returns type 'language' (and also has class 'call').

There are different ways your requirement could be implemented. You could support a literal string, or a symbol (as I showed), or even apply some kind of sophisticated analysis of the parse tree of the argument, such as accepting a dollar call and extracting from the resulting parse tree the RHS, and using that symbol as the component name. You could even through type detection of the argument's parse tree support some or all of these interfaces with a single function definition, although that would add complexity. I don't think that would be worth it; the way I wrote foo() above I think is the best design, since the implementation is simple, but it also provides maximum convenience for the caller, since they can specify the target list component using an unquoted symbol.

See my answer at What is "{" class in R? for more information on R parse trees.

Community
  • 1
  • 1
bgoldst
  • 34,190
  • 6
  • 38
  • 64
  • Hi, yes, thanks! We can obtain the attribute through `lst[["attribute name"]]`, so `foo(lst,'CLICK')` may be a more natural way. But I still want to know is there a way to achieve by using '$'? The `CLICK` in `lst$CLICK` is not a symbol? – user1903382 Aug 05 '15 at 08:02