如何在R中高效复用重复代码?寻求替代<<-的规范方案
替代R中
<<-全局赋值的代码复用方案 我在R中合并两个数据集(爬取的科研作者机构隶属数据与Web of Science数据),由于ID变量格式混乱,需要多次执行「处理ID变量→合并→处理ID变量→合并」的流程。每次ID处理的逻辑各不相同,但合并环节的代码完全重复。我之前用<<-定义了全局赋值的函数来复用代码,但听说这是不良编码实践,想找不用<<-的替代方案,且因为任务特性无法用循环统一处理不同的ID操作。
原重复合并代码
b_suc <- merged_b[is.na(merged_b$cwts_organization_id)==F, ] b_suc <- subset(b_suc, select = c(contribs, cwts_organization_id)) merged <- merge(merged, b_suc, by="contribs", all.x=T) merged$cwts_organization_id.x <- ifelse(is.na(merged$cwts_organization_id.x)==T & is.na(merged$cwts_organization_id.y)==F, merged$cwts_organization_id.y, merged$cwts_organization_id.x) merged <- rename(merged, cwts_organization_id = cwts_organization_id.x) merged <- subset(merged, select = -c(cwts_organization_id.y)) succes <- c(succes, sum(is.na(merged$cwts_organization_id)==F)) unsuc <- merged[is.na(merged$cwts_organization_id)==T, ] unsuc <- subset(unsuc, select = -c(cwts_organization_id, short_name, city, id))
原全局赋值函数(使用<<-)
append_end <- function(){ b_suc <<- merged_b[is.na(merged_b$cwts_organization_id)==F, ] b_suc <<- subset(b_suc, select = c(contribs, cwts_organization_id)) merged <<- merge(merged, b_suc, by="contribs", all.x=T) merged$cwts_organization_id.x <<- ifelse(is.na(merged$cwts_organization_id.x)==T & is.na(merged$cwts_organization_id.y)==F, merged$cwts_organization_id.y, merged$cwts_organization_id.x) merged <<- rename(merged, cwts_organization_id = cwts_organization_id.x) merged <<- subset(merged, select = -c(cwts_organization_id.y)) succes <<- c(succes, sum(is.na(merged$cwts_organization_id)==F)) unsuc <<- merged[is.na(merged$cwts_organization_id)==T, ] unsuc <<- subset(unsuc, select = -c(cwts_organization_id, short_name, city)) }
替代方案:函数返回值+显式赋值
核心思路是让函数接收需要处理的输入数据,把所有处理后的结果打包成列表返回,然后在全局环境中显式更新变量,完全规避隐式全局赋值的问题。
改写后的函数
process_merge <- function(merged_current, merged_b_current, succes_current) { # 筛选出有有效机构ID的merged_b子集 b_suc <- merged_b_current[!is.na(merged_b_current$cwts_organization_id), ] b_suc <- b_suc[, c("contribs", "cwts_organization_id"), drop = FALSE] # 执行左连接合并 merged_new <- merge(merged_current, b_suc, by = "contribs", all.x = TRUE) # 用右侧的机构ID填充左侧的缺失值 merged_new$cwts_organization_id.x <- ifelse( is.na(merged_new$cwts_organization_id.x) & !is.na(merged_new$cwts_organization_id.y), merged_new$cwts_organization_id.y, merged_new$cwts_organization_id.x ) # 重命名列并移除多余的y列 merged_new <- dplyr::rename(merged_new, cwts_organization_id = cwts_organization_id.x) merged_new <- merged_new[, !names(merged_new) %in% "cwts_organization_id.y", drop = FALSE] # 更新成功匹配的计数 succes_new <- c(succes_current, sum(!is.na(merged_new$cwts_organization_id))) # 提取未匹配成功的记录子集 unsuc_new <- merged_new[is.na(merged_new$cwts_organization_id), ] unsuc_new <- unsuc_new[, !names(unsuc_new) %in% c("cwts_organization_id", "short_name", "city", "id"), drop = FALSE] # 返回所有处理后的结果 return(list( merged = merged_new, succes = succes_new, unsuc = unsuc_new )) }
使用方式
每次处理完ID变量后,调用函数并显式更新全局变量:
# 调用函数,传入当前的merged、merged_b、succes merge_result <- process_merge(merged, merged_b, succes) # 依次更新全局变量 merged <- merge_result$merged succes <- merge_result$succes unsuc <- merge_result$unsuc
方案优势
- 彻底抛弃
<<-的隐式全局赋值,代码逻辑透明,调试时能清晰追踪变量变化 - 函数的输出完全由输入决定,没有副作用,便于单独测试某一步的合并逻辑
- 显式赋值的方式让全局变量的更新过程一目了然,避免意外修改其他变量
内容的提问来源于stack exchange,提问作者EmilA
相关产品推荐
相关产品推荐

