2017-01-29 6 views
4

des laufen Lassen Sie sagen, dass ich einen einfachen Ausdruck haben, wie:einen beliebigen Ausdruck oder String, identifizieren Variablen erforderlich Gegeben Ausdruck

ifelse(x < 0, 1,0) 

Ich möchte dies zu einem gewissen Funktion zu übergeben, wie all.vars wie vorgesehen durch @RichScriven. So das Ergebnis der Zeichenvektor sein würde: x

rowSums(dat[c("x","y","z")]) 

In diesem Fall würde ich gerne sehen: c("dat", "x","y","z").

Es gibt jedoch komplexere Beispiele:

ifelse(x < 0, rowsums(dat[c("x","y","z"]), 0) 

In diesem Fall Ich mag würde, um zu sehen: c("x", "dat", "x","y","z")

Es sieht aus wie der erste Teil meiner Frage von all.vars beantwortet wurde, aber das doesn arbeite nicht für den zweiten Teil.

+2

'all.vars (Zitat (ifelse (x <0, 1, 0)))' arbeitet für der erste. Aber auf der zweiten wird das wegen der Zeichenwerte in der Spaltenuntermenge nicht fliegen. –

+0

@akaDrHouse Ich kann mir ehrlich gesagt keine gute Lösung vorstellen! Auch Downvotes ohne konstruktiven Kommentar kühlen nicht ab. –

+0

@RichScriven 'all.vars' ist ein guter Start, danke! –

Antwort

4

sollte Folgendes tun, was Sie wollen:

recurse_ast <- function(x) { 
    if (is.atomic(x) || is.name(x)){} 
    else if (is.call(x)) { 
    if(identical(quote(`[`),x[[1]])) { 
     ret <- c() 
     for(i in seq(2,length(x))) { 
     if(is.call(x[[i]]) && x[[i]][[1]] == 'c') { 
      for(j in seq(2,length(x[[i]]))) { 
      if(!is.name(x[[i]][[j]])){ 
       ret <- c(ret,x[[i]][[j]]) 
      } 
      } 
     } 
     } 
     ret 
    } else unlist(lapply(x,recurse_ast)) 
    } else if (is.pairlist(x) || is.expression(x)) { 
     unlist(lapply(x,recurse_ast)) 
    } else { 
    # User supplied incorrect input 
    stop("Don't know how to handle type ", typeof(x), 
     call. = FALSE) 
    } 
} 

get_requirements <- function(x) { 
    c(all.vars(x),recurse_ast(x)) 
} 

Für alle Ihre Beispiele hat dies das richtige Ergebnis (einen kleinen Syntaxfehler in Ihrem letzten Beispiel korrigiert hat):

> get_requirements(quote(ifelse(x < 0, 1,0))) 
[1] "x" 
> get_requirements(quote(rowSums(dat[c("x","y","z")]))) 
[1] "dat" "x" "y" "z" 
> get_requirements(quote(ifelse(x < 0, rowsums(dat[c("x","y","z")], 0)))) 
[1] "x" "dat" "x" "y" "z" 

bearbeiten : Betrachtet man die letzte Ausgabe, ist es jedoch wahrscheinlich ratsam, die Ergebnisse von recurse_ast und all.vars getrennt zu halten, da es keine Möglichkeit gibt, zwischen der Variablen x und der in Subsetting verwendeten Zeichenkette "x" zu unterscheiden. Wahrscheinlich wäre es auch nützlich, die Variable beizubehalten, die Teilmenge ist.

Edit: Wenn der Ausdruck als String nur verfügbar ist, ist folgendes möglich:

> get_requirements_from_string <- function(s) { 
+ get_requirements(parse(text=s)) 
+ } 
> get_requirements_from_string("ifelse(x < 0, 1, 0)") 
[1] "x" 
+0

Das ist großartig. Ich habe es gerade gegen eine Reihe von Randfällen getestet und es funktioniert sogar gegen einzelne zitierte Anforderungen. –

+0

Gibt es eine Anpassung, die wir hier für Situationen vornehmen könnten, in denen die Eingabe eine Zeichenkette ist, ich meine, bereits zitiert, 'req <-" ifelse (x <0, 1, 0) "' 'get_requirements (req)' –

+0

Ja - Siehe meine Bearbeitung. Ich musste einen Fall für "i.expression (x)" hinzufügen, der fehlte, da es zuvor nicht notwendig war. –

Verwandte Themen