2013-01-04 113 views
4

我想製作一個基本的概要分析工具,它可以收集時間戳並用筆記產生運行時間。唯一的問題是我無法弄清楚如何在不使用全局變量的情況下做到這一點。實現我試圖實現的功能的「正確」方式是什麼?如果R已經內置了這個功能,那真棒,但是我真正想要弄清楚的是如何避免使用全局變量並編寫更強大的代碼。避免全局變量

timeStamps = c() 
runTimes = list() 

appendRunTimes <- function(note) { 
    if(length(timeStamps) < 1) { 
    timeStamps <<- Sys.time() 
    } 
    else { 
    timeStamps <<- c(timeStamps, Sys.time()) 
    diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1] 
    runTimes <<- c(runTimes, format(diff)) 
    names(runTimes)[length(runTimes)] <<- note 
    } 

} 


appendRunTimes('start') 
Sys.sleep(4) 
appendRunTimes('test') 
+3

我會看'system.time'代碼的想法..或使用它!您還可以查看一些基準測試軟件包的代碼(例如'microbenchmark')。 – Justin

+0

除了其他建議外,請參閱「R介紹」(http://cran.r-project.org/doc/manuals/R-intro.pdf)第10.7節,第50頁(2.15.2修訂版)。 –

回答

7

下面是使用閉包的例子改寫:

RTmonitor <- local({ 
    timeStamps = c() 
    runTimes = list() 

    list(
    appendRunTimes=function(note) { 
     if(length(timeStamps) < 1) { 
     timeStamps <<- Sys.time() 
     } 
     else { 
     timeStamps <<- c(timeStamps, Sys.time()) 
     diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1] 
     runTimes <<- c(runTimes, format(diff)) 
     names(runTimes)[length(runTimes)] <<- note 
     } 
    }, 
    viewRunTimes=function() { 
     return(list(timeStamps=timeStamps,runTimes=runTimes)) 
    }) 
}) 


> RTmonitor$appendRunTimes("start") 
> RTmonitor$appendRunTimes("test") 
> RTmonitor$viewRunTimes() 
$timeStamps 
[1] "2013-01-04 18:39:12 EST" "2013-01-04 18:39:21 EST" 

$runTimes 
$runTimes$test 
[1] "8.855587 secs" 

觀察到的值存儲在瓶蓋內,而不是在全球環境:

> timeStamps 
Error: object 'timeStamps' not found 
> runTimes 
Error: object 'runTimes' not found 
> RTmonitor$timeStamps 
NULL 
> RTmonitor$runTimes 
NULL 

更多閱讀關於關閉和避免全局變量:

+0

你只有一步從R.oo或可能使用ReferenceClasses在這裏,不是嗎? – Spacedman

+0

@Spacedman想發佈一個R.oo或RefClass解決方案嗎? :-)我很想看看其他人提出了什麼。 –

4

這裏現在做到這一點使用ReferenceClasses:

RTmonitor = setRefClass("RTmonitor", 
    fields=list(
    timeStamps="POSIXct", 
    runTimes = "list" 
    ), 
    methods=list(
    appendRunTimes=function(note){ 
     if(length(timeStamps)==0){ 
     timeStamps <<- Sys.time() 
     }else{ 
     timeStamps <<- c(timeStamps, Sys.time()) 
     diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1] 
     runTimes <<- c(runTimes, format(diff)) 
     names(runTimes)[length(runTimes)] <<- note 
     } 
    } 
    ) 
) 

現在已經定義一個類,實例化一個對象,並使用它:

> r = RTmonitor$new() 
> r$appendRunTimes("start") 
> r$appendRunTimes("test") 
> r 
Reference class object of class "RTmonitor" 
Field "timeStamps": 
[1] "2013-01-05 14:52:25 GMT" "2013-01-05 14:52:31 GMT" 
Field "runTimes": 
$test 
[1] "5.175815 secs" 

與閉包方法非常相似,但更形式化。例如,我必須將timeStamps字段定義爲POSIXct。你也可以用這種方法創建多個對象,並且它們獨立工作 - 你必須編寫一個閉包構造器來封閉閉包。