How to use with/within inside a function?

前端 未结 3 1461
[愿得一人]
[愿得一人] 2020-12-10 07:30

I\'m struggling to understand why does this doesn\'t work.

df <- data.frame(a=1:10, b=1:10)

foo <- function(obj, col) {
   with(obj, ls())
   with(obj         


        
相关标签:
3条回答
  • 2020-12-10 07:33

    with is handy and improves readability in an interactive context but can hurt your brain in a programming context where you are passing things back and forth to functions and dealing with things in different environments. In general within R, using symbols rather than names is a sort of "semantic sugar" that is convenient and readable in interactive use but mildly deprecated for programming [e.g. $, subset]). If you're willing to compromise as far as using a name ("a") rather than a symbol (a) then I would suggest falling back to the simpler obj[[col]] rather than using with here ...

    So, as a self-contained answer:

    foo <- function(object,col) {
       print(names(object))
       print(object[[col]])
    }
    

    If you wanted to allow for multiple columns (i.e. a character vector)

    foo <- function(object,col) {
       print(names(object))
       print(object[col])
    }
    

    edit: refraining from using subset with a function, at @hadley's suggestion

    (this will print the answer as a data frame, even if a single column is selected, which may not be what you want).

    0 讨论(0)
  • 2020-12-10 07:34

    In function argument col is evaluated before using in function with (that opposite to interactive use). Here you have two solutions to this problem.

    foo1 <- function(obj, col) {
              with(obj, print(eval(col)))
            }
    foo1(mydf, quote(a))# here you have to remember to quote argument
    
    
    foo2 <- function(obj, col) {
              col <- as.expression(as.name(substitute(col)))#corrected after DWIN comment
              with(obj, print(eval(col)))
            }
    foo2(mydf, a)# this function does all necessary stuff
    
    0 讨论(0)
  • 2020-12-10 07:42

    Anything that is passed to a function must be an object, a string or a number. There are two problems with this:

    1. In this case you're trying to pass "a" as an object, when you should really be passing it like a string.
    2. with(obj, ls())) will return to the functions environment (function scoping) and not the screen unless you tell it to print.

    What you want is more like:

    foo <- function(obj, col) {
           print(with(obj, ls()))
           with(obj, print(obj[[col]]))
        }
    
    foo(df, "a")
    

    Or if you're only looking for the one column to be printed:

    foo <- function(obj, col) {
               with(obj, print(obj[[col]]))
            }
    
    foo(df, "a")
    
    0 讨论(0)
提交回复
热议问题