在 R 中模拟动态作用域以按任意函数进行过滤
Emulate dynamic scoping in R to filter by arbitrary functions
我在一个目录下有很多文件,我想根据它们的内容是否满足某个条件,将它们分配到两个新创建的子目录中。而且,我需要对多个目录执行这个操作,而且每次的条件可能都不一样。
我想我会这样做的方法是创建一个读取文件的高阶函数,从每个文件中提取感兴趣的 属性,然后应用条件(作为参数提供以函数的形式)逐元素到结果向量的值:
filter.by.property <- function(where, funct) {
setwd(where)
paths <- list.files(".", pattern = ".file")
Robjects <- Map(read.file, paths)
values <- sapply(Robjects, function(x) property_of_interest(x))
passes <- Filter(funct, paths)
dir.create("dir1")
dir.create("dir2")
file.copy(passes, paste("./dir1/", 1:length(passes), ".file", sep = ""))
file.copy(paths[!paths %in% passes], paste("./dir2/", (length(passes) + 1):length(paths), ".file", sep = ""))
}
问题是我希望条件指定函数(在 funct
参数中提供)能够访问 values
向量。例如:
ten.biggest <- function(path) {
Robject <- read.file(path)
property_of_interest(x) %in% tail(sort(values), 10)
}
filter.by.property(<place>, ten.biggest)
由于 R 是词法范围的,它会在定义 ten.biggest
的环境(全局环境)中查找 values
,而不是在调用它的环境中(即在 filter.by.property
).我可以通过在 filter.by.property
中对 values
使用全局赋值来解决这个问题,但除非绝对必要,否则我宁愿不这样做。我也可以提供 values
作为 ten.biggest
的另一个参数,但这样函数将不再是一元的,我不确定它如何(甚至是否)仍然可以在 [=22] 中使用=].
我尝试的一个解决方案是重写 ten.biggest
如下
ten.biggest <- function(path) {
Robject <- read.file(path)
property_of_interest(x) %in% tail(sort(eval.parent(parse(text = values))), 10)
}
但这没有用。
有什么方法可以在 R 中模拟动态作用域来完成这项工作吗?通过阅读相关的 StackExchange 问题,似乎 body
函数可能有所帮助,但我不知道如何将它应用到我的问题中。
我找到了一个不依赖切换环境的解决方案。我允许 ten.biggest
接受两个参数,并在 filter.by.property
内部定义了一个辅助函数 outer_fxn
,通过设置其参数之一将二元函数转换为一元函数。然后二进制 ten.biggest
函数可以通过后者的 funct
参数传递给 filter.by.property
,ten.biggest
的 vals
参数被设置为 values
outer_fxn
,然后可以在 Filter
:
中使用生成的一元函数
ten.biggest <- function(path, vals) {
Robject <- read.file(path)
property_of_interest(x) %in% tail(sort(vals), 10)
}
filter.by.property <- function(where, funct) {
setwd(where)
paths <- list.files(".", pattern = ".file")
Robjects <- Map(read.file, paths)
values <- sapply(Robjects, function(x) property_of_interest(x))
outer_fxn <- function(x) { funct(x, values) }
passes <- Filter(outer_fxn, paths)
dir.create("dir1")
dir.create("dir2")
file.copy(passes, paste("./dir1/", 1:length(passes), ".file", sep = ""))
file.copy(paths[!paths %in% passes], paste("./dir2/", (length(passes) + 1):length(paths), ".file", sep = ""))
}
我在一个目录下有很多文件,我想根据它们的内容是否满足某个条件,将它们分配到两个新创建的子目录中。而且,我需要对多个目录执行这个操作,而且每次的条件可能都不一样。
我想我会这样做的方法是创建一个读取文件的高阶函数,从每个文件中提取感兴趣的 属性,然后应用条件(作为参数提供以函数的形式)逐元素到结果向量的值:
filter.by.property <- function(where, funct) {
setwd(where)
paths <- list.files(".", pattern = ".file")
Robjects <- Map(read.file, paths)
values <- sapply(Robjects, function(x) property_of_interest(x))
passes <- Filter(funct, paths)
dir.create("dir1")
dir.create("dir2")
file.copy(passes, paste("./dir1/", 1:length(passes), ".file", sep = ""))
file.copy(paths[!paths %in% passes], paste("./dir2/", (length(passes) + 1):length(paths), ".file", sep = ""))
}
问题是我希望条件指定函数(在 funct
参数中提供)能够访问 values
向量。例如:
ten.biggest <- function(path) {
Robject <- read.file(path)
property_of_interest(x) %in% tail(sort(values), 10)
}
filter.by.property(<place>, ten.biggest)
由于 R 是词法范围的,它会在定义 ten.biggest
的环境(全局环境)中查找 values
,而不是在调用它的环境中(即在 filter.by.property
).我可以通过在 filter.by.property
中对 values
使用全局赋值来解决这个问题,但除非绝对必要,否则我宁愿不这样做。我也可以提供 values
作为 ten.biggest
的另一个参数,但这样函数将不再是一元的,我不确定它如何(甚至是否)仍然可以在 [=22] 中使用=].
我尝试的一个解决方案是重写 ten.biggest
如下
ten.biggest <- function(path) {
Robject <- read.file(path)
property_of_interest(x) %in% tail(sort(eval.parent(parse(text = values))), 10)
}
但这没有用。
有什么方法可以在 R 中模拟动态作用域来完成这项工作吗?通过阅读相关的 StackExchange 问题,似乎 body
函数可能有所帮助,但我不知道如何将它应用到我的问题中。
我找到了一个不依赖切换环境的解决方案。我允许 ten.biggest
接受两个参数,并在 filter.by.property
内部定义了一个辅助函数 outer_fxn
,通过设置其参数之一将二元函数转换为一元函数。然后二进制 ten.biggest
函数可以通过后者的 funct
参数传递给 filter.by.property
,ten.biggest
的 vals
参数被设置为 values
outer_fxn
,然后可以在 Filter
:
ten.biggest <- function(path, vals) {
Robject <- read.file(path)
property_of_interest(x) %in% tail(sort(vals), 10)
}
filter.by.property <- function(where, funct) {
setwd(where)
paths <- list.files(".", pattern = ".file")
Robjects <- Map(read.file, paths)
values <- sapply(Robjects, function(x) property_of_interest(x))
outer_fxn <- function(x) { funct(x, values) }
passes <- Filter(outer_fxn, paths)
dir.create("dir1")
dir.create("dir2")
file.copy(passes, paste("./dir1/", 1:length(passes), ".file", sep = ""))
file.copy(paths[!paths %in% passes], paste("./dir2/", (length(passes) + 1):length(paths), ".file", sep = ""))
}