编写R-light方式 – 避免for循环

我正在浏览我的一个.R文件并稍微清理一下我试图更熟悉用r -ight方式编写代码.作为初学者,我最喜欢的出发点之一是摆脱for()循环并尝试将表达式转换为函数式编程形式.
所以这是场景:

我正在将一堆data.frames组装成一个列表供以后使用.

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")
  }
}

由于我在这里工作的列表,我想到了lapply函数.我尝试使用lapply函数处理这项工作似乎都很正常,但只是乍一看.如果我写

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

最后一行打印出几乎我要找的东西.但是,如果我再看一下dataList中data.frames的实际名称:

lapply (dataList, colnames)

我看到没有对初始字符串进行任何更改.

那么如何重写for()循环并将其转换为函数式编程形式呢?
如何以有效的方式替换两个字符串“foo”和“bar”?由于gsub()函数仅将长度为1的字符向量作为其模式参数.

最佳答案
您的代码几乎可以工作 – 但请记住,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)

转载注明原文:编写R-light方式 – 避免for循环 - 代码日志