2010-03-14 27 views
4

我正在通過我的.R文件之一,並通過清理它一點點,我想更熟悉編寫代碼的r-ight方式。作爲一名初學者,我最喜歡的起點之一是擺脫for()循環,並嘗試將表達式轉換爲函數式編程形式。 因此,這裏是場景:編碼R-ight的方式 - 避免for循環

我正在裝入一堆data.frameslist供以後使用。

dataList <- list (dataA, 
        dataB, 
        dataC, 
        dataD, 
        dataE 
       ) 

現在我想看看每個data.frame的列名稱並替換某些字符串。例如,我喜歡用「baz」替換每個「foo」和「bar」。目前我正在用for()循環完成工作,看起來有點尷尬。

colnames(dataList[[1]]) 
[1] "foo"  "code" "lp15"  "bar"  "lh15" 
colnames(dataList[[2]]) 
[1] "a"  "code" "lp50"  "ls50"  "foo" 

matchVec <- c("foo", "bar") 
for (i in seq(dataList)) { 
    for (j in seq(matchVec)) { 
    colnames (dataList[[i]])[grep(pattern=matchVec[j], x=colnames (dataList[[i]]))] <- c("baz") 
    } 
} 

因爲我有list在這裏工作我想到了lapply功能。我用lapply函數處理這項工作的嘗試似乎都看起來不錯,但只是一見鍾情。如果我寫

f <- function(i, xList) { 
    gsub(pattern=c("foo"), replacement=c("baz"), x=colnames(xList[[i]])) 
} 
lapply(seq(dataList), f, xList=dataList) 

最後一行打印出我正在尋找的幾乎所有東西。但是,如果我再看看在data.frames在DataList控件的實際名稱:

lapply (dataList, colnames) 

我看到沒有發生任何變化初始字符串做。

那麼如何重寫for()循環並將其轉換爲函數式編程形式呢? 如何以有效的方式替換兩個字符串「foo」和「bar」?由於gsub()函數僅將一個長度爲1的字符向量作爲其參數pattern

回答

9

您的代碼幾乎可行 - 但請記住R會創建您修改的對象的副本(即按值傳遞語義)。所以,你需要新的字符串明確分配給colnames,像這樣:

dataA <- dataB <- data.frame(matrix(1:20,ncol=5)) 
names(dataA) <- c("foo","code","lp15","bar","lh15") 
names(dataB) <- c("a","code","lp50","ls50","foo") 
dataList <- list(dataA, dataB) 
f <- function(i, xList) { 
    colnames(xList[[i]]) <- gsub(pattern=c("foo|bar"), replacement=c("baz"), x=colnames(xList[[i]])) 
    xList[[i]] 
} 
dataList <- lapply(seq(dataList), f, xList=dataList) 

新的名單將與更換名稱的數據幀。就替換foo和bar而言,只需在gsub(「foo | bar」)的正則表達式中使用替代模式即可。

注意,順便說一句,你沒有通過索引到你的列表要做到這一點 - 只要使用你的名單直接的元素進行動作的功能:

f <- function(df) { 
    colnames(df) <- gsub(pattern=c("foo|bar"), replacement=c("baz"), x=colnames(df)) 
    df 
} 
dataList <- lapply(dataList, f) 
+0

@Leo感謝獅子座!它工作非常順利。特別是第二種方法通過使索引冗餘而變得非常優雅。 – mropa 2010-03-14 09:26:52