2012-03-21 62 views
2

我試圖爲循環中的每個元素分配一個函數。 我想函數使用的變量的值,但他們使用的變量的最後一個值:在循環中分配函數

assign.instrumentslist = function() 
{ 
    for(instList in lists.instruments) 
    { 
    assign(
     paste("test", instList, sep="."), 
     function() {print(instList)}, 
     envir = .GlobalEnv 
    ) 
    } 
} 

lists.instruments = c("CL", "HO", "GC") 
assign.instrumentslist() 
test.CL() 
# return "GC" 

THX

回答

4

也許這是最簡單的方法:

assign.instrumentslist = function() { 
    for(instList in lists.instruments) { 
    local({ 
     i <- instList 
     assign(
      paste("test", instList, sep="."), 
      function() {print(i)}, 
      pos = .GlobalEnv 
      ) 
    }) 
    } 
} 

的關鍵是在函數的封閉環境中創建本地對象(i)。 在此示例中,環境由local生成。

這是一個非常非常糟糕的黑客:

lapply(lists.instruments, 
    function(x) .GlobalEnv[[paste("test1", x, sep=".")]] <- function() print(x)) 
+1

+1因爲它有效,但你應該因爲把它放在這裏而受到懲罰! ;-) – 2012-03-21 09:10:58

+0

請保持它自己;-p – kohske 2012-03-21 09:13:51

+0

Thx爲您的幫助!奧利維爾 – user1281273 2012-03-21 09:46:06

2

這有什麼錯用的參數?

AsItShouldBeDone <- 
function(x){ 
    print(x) 
} 

> AsItShouldBeDone('CL') 
[1] "CL" 

這是關於儘可能多的打字工作:給CL作爲參數,而不是額外添加到函數的名稱。這就是你應該如何去做的。

您的解決方案有什麼問題? :

  • 使用assign():這是非常不明智的全局環境從一個函數中的任何語言改變,絕對完全違背思維中的R方式。所以不要。我碰巧在我的工作區中有一個名爲test.CL的數據框。那麼,現在已經過去了......
  • 用不同的名字創建不同的函數,所有的代碼都是相同的。這是爲什麼?如果您試圖找到一個快捷方式爲不同類別分配S3方法,請嘗試以下操作。在任何其他情況下,使用參數,使您的功能做自己應該

    test.CL <- test.HO <- test.GC <- function(x) print(x)

  • 期待一個變量的值是一個函數從一個循環內進行硬編碼。不,這不對。 [R告訴你這是函數:

    > test.CL

    function() {print(instList)}

    <environment: 0x05e32224>

所以它的作用是相當明顯的:它在環境中給出的環境中打印instList。你的第一個功能是由哪個環境創建的。其中包含循環後instList的值。哪一個是最後的價值。

該機制被Koshke的方法破解。有用。這不是因爲它的作用,你應該使用它,相反;像這樣的黑客環境可能會產生非常有趣的副作用,而且絕不是穩定的代碼。另外,如前所述:

使用基督徒的基本知識!

+0

我必須謙虛地不同意,而不是解釋正在發生的事情 - 這是發生的 - 但與另一點。我已經看到了很多OP的嘗試用例。他想要一個可以定義的函數來返回一些特定的東西,而不是被傳入。我已經看到這個習慣用法了很多,但現在不記得實際的例子。由於環境問題,他只是錯誤地做了這件事。 – 2012-03-21 09:15:07

+0

@GavinSimpson:但是如果你創建了三個函數,你在名字中指定了你想返回的內容,那麼如果寫一個函數,你在參數中指定了你想要返回的內容,那麼這樣做會更好嗎?我能看到的唯一用例是爲S4課程中的每個插槽快速創建getter和setter,而無需全部輸入,但即使如此,我仍然認爲這種錯誤的編碼習慣。另外,技術上這些參數中的值可以改變,這會讓你的函數突然返回其他東西。這不是穩定的代碼。 – 2012-03-21 09:23:41

+0

我並不是說我會做OP的工作,我希望/懷疑所示的例子是真實的用例(只是一個可重現的例子來說明問題),但上述可以並且通過很多的人,他們中的許多人比我實施它的人更聰明。 – 2012-03-21 09:30:49

2

我可以解釋行爲,但不知道解決問題的正確方法是什麼(環境會讓我的頭部受傷)。

問題是您的匿名函數會提取一個環境。它會在其中查找對象的環境,包括instList。在第一次迭代中,它獲得這種環境<environment: 0x28e19a8>,這是你的函數當前環境正在評估(assign.instrumentslist()):

Browse[2]> environment() 
<environment: 0x28e19a8> 

在循環的下一次迭代的instList在目前的環境<environment: 0x28e19a8>值變更爲"HO"。現在test.CL()test.HO()都具有相同的環境,因此請參閱相同的instList,該值現在具有值"HO"。在test.GC()的最後一次迭代中發生同樣的事情。下面的調試記錄表明這樣的:

debug at #5: assign(paste("test", instList, sep = "."), function() { 
    print(instList) 
}, envir = .GlobalEnv) 
Browse[2]> 
debug at #3: instList 
Browse[2]> environment(test.CL) 
<environment: 0x28e19a8> 
Browse[2]> eval(instList, environment(test.CL)) 
[1] "CL" 
Browse[2]> 
debug at #5: assign(paste("test", instList, sep = "."), function() { 
    print(instList) 
}, envir = .GlobalEnv) 
Browse[2]> 
debug at #3: instList 
Browse[2]> environment(test.CL) 
<environment: 0x28e19a8> 
Browse[2]> eval(instList, environment(test.CL)) 
[1] "HO" 

當循環結束後,的assign.instrumentslist()<environment: 0x28e19a8>評價環境中,仍然存在,因爲它也是你的三個功能環境。它們都指向相同的環境,並使用在循環的最後一次迭代期間設置的值instList