Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I list objects sorted by date?

Tags:

r

This would be very useful to me. Can I sort the output of ls() by date (last modified or something similar)?

Context: I have a very messy workspace full of various data.frames, variables and plots. I need to find a data.frame and I cannot remember what I called it, only that I was working on it recently. Hence ls() sorted by date modified would help me work out what I called it.

To clarify: This is not a question about using history(). I use history frequently and often save it when I think it might be required. In this case, history does not cover the period required, so I cannot find the data.frame using history().

Additional: Aside from the stated task of finding a recently created data.frame, it would be very useful, in general, to be able to sort ls() according to date. I have well over 100 objects in the workspace that I have been working on for over 2 years (searching 2 years of history does not sound fun either). If it were possible to sort these objects into a chronological order then I would have some idea of which were newer (and possibly edited) and which were older (and perhaps original).

I have attempted to improve my workflow by slowly moving individual objects into smaller, related workspaces. But this process will take time, and is essentially pointless (as I am nearing the end of data analysis anyway).

like image 416
Frank Zafka Avatar asked Jan 23 '13 11:01

Frank Zafka


4 Answers

Something you might try is automating the logging of modifications to variables of interest using the makeActiveBinding function. You could then use the log to sort the output of ls() by modification time.

One caveat is that, using this method, tracking has to be set up before the variable is first used.

.change.log <- list()
track <- function(variable) {
    makeActiveBinding(variable,
        function(v) 
            if (! missing(v)) 
            .change.log[[variable]] <<- c(.change.log[[variable]], 
                                           as.list(Sys.time())),
        .GlobalEnv)
}

track('x')
x <- 1
.change.log
x <- 2
.change.log

Each time x is modified, the anonymous function supplied to makeActiveBinding gets called with v equal to the new value. This function also gets called when x is referenced, but with nothing supplied to v in this case, hence the conditional with missing(v)---we only want to update the log when the value changes.


EDIT

After further consideration, a better alternative to makeActiveBinding would be to install a modification logger via the function addTaskCallback. The code below creates an automated logger that records timestamps by variable name every time the <- operator is used at the top level.

# define a log maker function. This returns a new logger function
# bound with a fresh log.
mk.log <- function() {
    log <- list()
    # handler functions have to have these four args, but we only use the first.
    function(expr, value, ok, visible) {
        if (class(expr) == '<-') {
            # convert the assignment call to a list, so the 
            # variable name can be extracted
            call.list <- as.list(expr)
            # extract the name of the variable being affected, and 
            # convert it to character, so we can use it as a list name
            variable <- as.character(call.list[[2]])
            # append a timestamp to the log for this variable
            log[[variable]] <<- c(log[[variable]], list(Sys.time()))
        }
        # callback handlers need to return a bool
        return(TRUE)
    }
}

# assign the handler to .log, and install it.
addTaskCallback(.log <- mk.log(), name='log')

x <- 5
x <- 10
y <- 4

# read the log
environment(.log)$log

# $x
# $x[[1]]
# [1] "2013-01-25 10:24:26.581 EST"
# 
# $x[[2]]
# [1] "2013-01-25 10:24:26.585 EST"
# 
# 
# $y
# $y[[1]]
# [1] "2013-01-25 10:24:26.589 EST"
like image 105
Matthew Plourde Avatar answered Nov 19 '22 22:11

Matthew Plourde


Well, with a little creative hacking, you could write your own methods for your variables. E.g.:

datedmatrix<-function(data,nrow,ncol,...) {
    output <- matrix(data, nrow=nrow,ncol=ncol,...)
    attr(output,'create') <- date()
    return(output)
}
like image 22
Carl Witthoft Avatar answered Nov 19 '22 23:11

Carl Witthoft


No, but you should use the historyfunction to find its name through the latest commands you have run.

By default, history will show the last 25 lines of code, but you can request more by doing:

history(max.show = 100)

There is also a hard limit on the number of lines you can show. It is equal to the value of the environment variable R_HISTSIZE whose default is 512. But as the documentation says:

There is no limit on the number of lines of history retained during a session [...]

so you can do:

Sys.setenv("R_HISTSIZE" = 10000)
history(max.show = 10000)

and you should be able to see all your history since you started your session (assuming you ran less than 10000 lines of code.)

like image 2
flodel Avatar answered Nov 19 '22 23:11

flodel


You could use ls.str(mode="list").

Example output:

b : 'data.frame':   1 obs. of  1 variable:
 $ test: Factor w/ 1 level "a": 1
c : 'data.frame':   1 obs. of  1 variable:
 $ x: num 1

I don't think the creation time is stored with any R objects.

like image 1
Roland Avatar answered Nov 19 '22 22:11

Roland