2016-09-11 4 views
1
erwartet

Der erste Aufruf der Funktion f funktioniert, der zweite nicht. Wie kann ich einen String ("v") an die Funktion f übergeben, damit die Funktion wie erwartet funktioniert?So übergeben Sie eine Zeichenfolge als Parameter an eine Funktion, die eine Variable in R

library(data.table) 

f<-function(t,x) t[,deparse(substitute(x)),with=F] 

dat<-data.table(v="a") 

f(dat,v) 
# v 
# 1: a 

f(dat,eval(parse(text="v"))) 
# Error in `[.data.table`(t, , deparse(substitute(x)), with = F) : 
# column(s) not found: eval(parse(text = "v")) 
+5

Verwenden Sie 'mget()' wie in 'dat [, mget (col)]' oder '.SD' zusammen mit '.SDcols' wie in' dat [, .SD, .SDcols = Spalten] 'wobei' Spalten = "v" '. Wenn das gleiche Funktionsargument ein Symbol (der Spalte) * und * als Zeichenvektor hat, führt dies zu Problemen und Unklarheiten. – Arun

Antwort

3

Es wird keine Einzeiler mehr sein, aber Sie können testen, was Sie vorbei in:

library(data.table) 
library(purrr) 

dat <- data.table(v="a") 

f <- function(dt, x) { 

    # first, see if 'x' is a variable holding a string with a column name 

    seval <- safely(eval) 
    res <- seval(x, dt, parent.frame()) 

    # if it is, then get the value, otherwise substitute() it 

    if ((!is.null(res$result)) && inherits(res$result, "character")) { 
    y <- res$result 
    } else { 
    y <- substitute(x) 
    } 

    # if it's a bare name, then we deparse it, otherwise we turn 
    # the string into name and then deparse it 

    if (inherits(y, "name")) { 
    y <- deparse(y) 
    } else if (inherits(y, "character")) { 
    y <- deparse(as.name(x)) 
    } 

    dt[, y, with=FALSE] 

} 

f(dat,v) 
## v 
## 1: a 

f(dat, "v") 
## v 
## 1: a 

V <- "v" 
f(dat, V) 
## v 
## 1: a 

f(dat, VVV) 
#> throws an Error 

Ich schaltete es t-dt da Ich mag es nicht mit die Namen der eingebauten Funktionen (wie t()) als Variablennamen, es sei denn, ich muss wirklich. Es kann subtile Fehler in größeren Code-Blöcken einführen, die beim Debuggen frustrierend sein können.

Ich würde auch den safely() Anruf außerhalb der f() Funktion verschieben, um einen Funktionsaufruf jedes Mal zu speichern, wenn Sie f() ausführen. Sie können Old-School try() stattdessen verwenden, wenn Sie möchten, aber Sie müssen nach try-error überprüfen, die eines Tages brechen kann. Sie könnten auch tryCatch() wickeln, aber die safely() Weg scheint nur sauberer für mich.

+1

'dt' ist auch der Name einer eingebauten Funktion !! blöde T-Verteilung. Ich bevorzuge 'DT' – MichaelChirico

+0

wahr, aber es ist viel wahrscheinlicher, dass man Daten transponieren will als die Student t-Distribution (zumindest in meiner Verwendung :-) – hrbrmstr

Verwandte Themen