【发布时间】:2011-12-09 11:35:00
【问题描述】:
我正试图围绕闭包展开思考,我认为我发现了一个可能有用的案例。
我有以下工作要做:
- 一组用于清理状态名称的正则表达式,位于一个函数中
- 具有状态名称(上述函数创建的标准化形式)和状态 ID 代码的 data.frame,用于链接两者(“合并图”)
这个想法是,给定一些带有草率州名的data.frame(首都是否列为“华盛顿特区”、“华盛顿特区”、“哥伦比亚特区”等?),只有一个函数返回删除了州名称列且仅保留州 ID 代码的相同 data.frame。然后可以持续进行后续合并。
我可以通过多种方式做到这一点,但一种似乎特别优雅的方式是将合并映射和正则表达式和代码处理在闭包内的所有内容(遵循闭包是数据函数)。
问题 1:这是一个合理的想法吗?
问题 2:如果是这样,我如何在 R 中做到这一点?
这是一个愚蠢的简单干净状态名称函数,适用于示例数据:
cleanStateNames <- function(x) {
x <- tolower(x)
x[grepl("columbia",x)] <- "DC"
x
}
以下是最终函数将在其上运行的一些示例数据:
dat <- structure(list(state = c("Alabama", "Alaska", "Arizona", "Arkansas",
"California", "Colorado", "Connecticut", "Delaware", "District of Columbia",
"Florida"), pop08 = structure(c(29L, 44L, 40L, 18L, 25L, 30L,
22L, 48L, 36L, 13L), .Label = c("1,050,788", "1,288,198", "1,315,809",
"1,316,456", "1,523,816", "1,783,432", "1,814,468", "1,984,356",
"10,003,422", "11,485,910", "12,448,279", "12,901,563", "18,328,340",
"19,490,297", "2,600,167", "2,736,424", "2,802,134", "2,855,390",
"2,938,618", "24,326,974", "3,002,555", "3,501,252", "3,642,361",
"3,790,060", "36,756,666", "4,269,245", "4,410,796", "4,479,800",
"4,661,900", "4,939,456", "5,220,393", "5,627,967", "5,633,597",
"5,911,605", "532,668", "591,833", "6,214,888", "6,376,792",
"6,497,967", "6,500,180", "6,549,224", "621,270", "641,481",
"686,293", "7,769,089", "8,682,661", "804,194", "873,092", "9,222,414",
"9,685,744", "967,440"), class = "factor")), .Names = c("state",
"pop08"), row.names = c(NA, 10L), class = "data.frame")
还有一个示例合并图(实际的是将 FIPS 代码链接到状态,因此不能轻易生成):
merge_map <- data.frame(state=dat$state, id=seq(10) )
编辑在下面 crippledlambda 的回答的基础上,这里是对该函数的尝试:
prepForMerge <- local({
merge_map <- structure(list(state = c("alabama", "alaska", "arizona", "arkansas", "california", "colorado", "connecticut", "delaware", "DC", "florida" ), id = 1:10), .Names = c("state", "id"), row.names = c(NA, -10L ), class = "data.frame")
list(
replace_merge_map=function(new_merge_map) {
merge_map <<- new_merge_map
},
show_merge_map=function() {
merge_map
},
return_prepped_data.frame=function(dat) {
dat$state <- cleanStateNames(dat$state)
dat <- merge(dat,merge_map)
dat <- subset(dat,select=c(-state))
dat
}
)
})
> prepForMerge$return_prepped_data.frame(dat)
pop08 id
1 4,661,900 1
2 686,293 2
3 6,500,180 3
4 2,855,390 4
5 36,756,666 5
6 4,939,456 6
7 3,501,252 7
8 591,833 9
9 873,092 8
10 18,328,340 10
在我认为这个问题解决之前还有两个问题:
每次调用
prepForMerge$return_prepped_data.frame(dat)都很痛苦。有什么方法可以让我调用 prepForMerge(dat) 的默认函数?我猜没有给出它是如何实现的,但也许至少有一个默认 fxn 的约定....如何避免在 merge_map 定义中混合数据和代码?理想情况下,我会在其他地方清理 merge_map,然后将其抓住并存储在闭包内。
【问题讨论】:
-
对我来说,这似乎不是一个使用闭包的自然场所。
-
@hadley 您能否将其发布为答案(因为它在问题 1 的范围内),也许需要详细说明是什么使得这不是关闭的理想情况(是数据不'真的不需要更新吗?)?我在闭包的“如何”方面做得很好,但在“为什么/何时”使用它们时遇到了困难。
标签: r functional-programming closures