如何为列表中每个data.table逐一设置对应名称属性(FP方法)
解决data.table对象逐一对齐设置名称属性的问题
这个问题我熟!你想要的其实就是R里对应Scala zip+map的函数式操作,之前用sapply踩坑是因为它没帮你把两个列表的元素一一配对,而是把整个名称列表传给了每个data.table。来看看正确的做法:
先明确初始场景(修正变量名避免混淆)
library(data.table) # 生成原始data.table original_DT = data.table( ID = c("b","b","b","a","a","c"), a = 1:6, b = 7:12, c = 13:18 ) # 包装成列表 DT_list <- list(original_DT, original_DT, original_DT) # 待分配的名称向量 names_vec <- c("NAME1", "NAME2", "NAME3")
方法1:用基础R的Map()函数(最贴合你要的zip+map逻辑)
Map()是基础R里专门处理多列表逐项配对操作的函数,和Scala中zip后再map的逻辑完全一致:
# 逐项配对设置属性 Map(function(dt, name) setattr(dt, "name", name), DT_list, names_vec)
验证效果:
attr(DT_list[[1]], "name") # 输出: [1] "NAME1" attr(DT_list[[2]], "name") # 输出: [1] "NAME2" attr(DT_list[[3]], "name") # 输出: [1] "NAME3"
方法2:用tidyverse的purrr::walk2()(适合处理副作用操作)
如果你习惯用tidyverse的函数式工具,walk2()更适合这种只执行副作用(修改属性)、不需要返回值的场景:
library(purrr) walk2(DT_list, names_vec, ~setattr(.x, "name", .y))
同样能实现完全一致的效果,而且不会返回冗余的结果,代码更简洁。
为什么之前的sapply失败?
sapply的逻辑是:对第一个参数(DT列表)的每个元素,都传入完整的第二个参数(整个names向量)。这就导致每个data.table都被赋值了整个名称列表作为name属性,而不是单个名称。而Map/walk2会严格按位置配对两个列表的元素,保证每个data.table只对应一个名称。
内容的提问来源于stack exchange,提问作者Alejandro Alcalde
相关产品推荐
相关产品推荐

