4

When we have defined tens of functions - probably to develop a new package - it is hard to find out the name of a specific variable among many function names through ls() command.

In most of cases we are not looking for a function name - we already know they exist - but we want to find what was the name we assigned to a variable.

Any idea to solve it is highly appreciated.

oguz ismail
  • 1
  • 16
  • 47
  • 69
Ali
  • 9,440
  • 12
  • 62
  • 92
  • 2
    You may also find the apropos function useful, if you remember at least part of the name. – hadley Oct 27 '12 at 00:43

6 Answers6

5

If you want a function to do this, you need to play around a bit with the environment that ls() looks in. In normal usage, the implementation below will work by listing objects in the parent frame of the function, which will be the global environment if called at the top level.

lsnofun <- function(name = parent.frame()) {
    obj <- ls(name = name)
    obj[!sapply(obj, function(x) is.function(get(x)))]
}

> ls()
[1] "bar"           "crossvalidate" "df"           
[4] "f1"            "f2"            "foo"          
[7] "lsnofun"       "prod"         
> lsnofun()
[1] "crossvalidate" "df"            "f1"           
[4] "f2"            "foo"           "prod"

I've written this so you can pass in the name argument of ls() if you need to call this way down in a series of nested function calls.

Note also we need to get() the objects named by ls() when we test if they are a function or not.

Gavin Simpson
  • 170,508
  • 25
  • 396
  • 453
4

So perhaps

ls()[!ls()%in%lsf.str()]

Josh O'Brien's suggestion was to use

setdiff(ls(), lsf.str())

That function, after some conversions and checks, calls

x[match(x, y, 0L) == 0L]

which is pretty close to what I suggested in the first place, but is packed nicely in the function setdiff.

BenBarnes
  • 19,114
  • 6
  • 56
  • 74
  • 7
    Or (the same thing) `setdiff(ls(), lsf.str())` – Josh O'Brien Oct 26 '12 at 21:10
  • Is setdiff(x,y) the same as saying "what's in x that's not in y"? – Brandon Bertelsen Oct 26 '12 at 21:46
  • @AliSharifi, as Josh mentioned, his comment does the same thing as my answer. It's just packed differently and does some extra things which in this case don't seem necessary. However, since `setdiff` is more readable, it is now incorporated it into the answer as an alternative. – BenBarnes Oct 27 '12 at 12:21
4

Rather than sorting through the objects in your global environment and trying to seperate data objects from functions it would be better to store the functions in a different environment so that ls() does not list them (by default it only lists things in the global environment). But they are still accessible and can be listed if desired.

The best way to do this is to make a package with the functions in it. This is not as hard as it sometimes seems, just use package.skeleton to start.

Another alternative is to use the save function to save all your functions to a file, delete them from the global environment, then use the attach function to attach this file (and therefore all the functions) to the search path.

Greg Snow
  • 48,497
  • 6
  • 83
  • 110
  • 1
    +1 Or use `sys.source()` to source a `.R` files directly into a new environment and attach it to search path. I have an example of this in [another Answer](http://stackoverflow.com/a/13092757/429846) from today. – Gavin Simpson Oct 26 '12 at 21:37
1

So you just want the variable names, not the functions? This will do that.

ls()[!sapply(ls(), function(x) is.function(get(x)))]
sachleen
  • 30,730
  • 8
  • 78
  • 73
nograpes
  • 18,623
  • 1
  • 44
  • 67
  • 2
    Or alternatively `ls()[!ls()%in%lsf.str()]` – BenBarnes Oct 26 '12 at 21:05
  • 2
    No, this doesn't work. `ls()` is a character vector. None of the items in it will return true when `is.function` is used. (Try `f = function() 1; ls()[!sapply(ls(),is.function)]` as evidence). – David Robinson Oct 26 '12 at 21:06
  • @AliSharifi: you can just use (and accept) BenBarnes's posted answer. – David Robinson Oct 26 '12 at 21:10
  • @Ali this get's nograpes' answer a working: `ls()[!sapply(ls(), function(x) is.function(get(x)))]` – Tyler Rinker Oct 27 '12 at 02:12
  • @TylerRinker Thanks I edited the answer, but it seems should be peer-reviewed. – Ali Oct 27 '12 at 02:19
  • @Ali I'd caution about editing people's answers. Generally, I've seen people suggest edits to an answer but never have I seen a substantive edit to an answer on SO R tag. – Tyler Rinker Oct 27 '12 at 03:05
  • @TylerRinker Thanks for your attention but SO has added +2 reputation because of this edit! I am confused it is good or bad? – Ali Oct 27 '12 at 11:00
1

The following function lsos was previously posted on stackoverflow (link) - it gives a nice ordering of objects loaded in your R session based on their size. The output of the function contains the class of the object, which you can subsequently filter to get the non-function objects.

source("lsos.R")

A <- 1
B <- 1
C <- 1
D <- 1
E <- 1
F <- function(x) print(x)

L <- lsos(n=Inf)
L[L$Type != "function",]

This returns:

> lsos(n=Inf)
         Type Size Rows Columns
lsos function 5184   NA      NA
F    function 1280   NA      NA
A     numeric   48    1      NA
B     numeric   48    1      NA
C     numeric   48    1      NA
D     numeric   48    1      NA
E     numeric   48    1      NA

Or, with the filter, the function F is not returned:

> L[L$Type != "function",]
     Type Size Rows Columns
A numeric   48    1      NA
B numeric   48    1      NA
C numeric   48    1      NA
D numeric   48    1      NA
E numeric   48    1      NA
Community
  • 1
  • 1
Marc in the box
  • 11,769
  • 4
  • 47
  • 97
0

I keep this function in my .rprofile. I don't use it often but it's great when I have several environments, function and objects in my global environment. Clearly not as elegant as BenBarnes' solution but I never have to remember the syntax and can just call lsa() as needed. This also allows me to list specific environments. e.g. lsa(e)

lsa <- function(envir = .GlobalEnv) {
    obj_type <- function(x) {
        class(get(x))
    }
    lis <- data.frame(sapply(ls(envir = envir), obj_type))
    lis$object_name <- rownames(lis)
    names(lis)[1] <- "class"
    names(lis)[2] <- "object"
    return(unrowname(lis))
}
Maiasaura
  • 32,226
  • 27
  • 104
  • 108
  • > lsa() Error in data.frame(M = "dgCMatrix", a = "matrix", accFile = "function", : arguments imply differing number of rows: 1, 2. Any idea? – Ali Oct 26 '12 at 21:29
  • Tried to replicate it several ways but couldn't. :/ – Maiasaura Oct 26 '12 at 21:37
  • But the .rprofile was interesting. Maybe better to share all this sort of tools in the .rprofiles to the other people – Ali Oct 26 '12 at 21:39
  • What happens if an object has multiple classes? Won't that cause `obj_type` to return vectors of different lengths? If so, dropping the `data.frame()` call and using `lapply()` would leave `lis` as a list, which would be robust to this. Or concatenate the result of `class(get(x))` into a string: `paste(class(get(x)), sep = ", ")` for example. – Gavin Simpson Oct 26 '12 at 22:12