替换列表元素时保留其属性的Base R实现方法
问题描述
现有如下R列表:
lst <- list( a = structure("x", class = "foo", type = "bar"), b = "y" ) str(lst) #> List of 2 #> $ a: 'foo' chr "x" #> ..- attr(*, "type")= chr "bar" #> $ b: chr "y"
我希望在替换其中class为foo的元素时自动保留该元素的原有属性,已手动实现预期效果:
res <- (function(x, i, value) { attrs <- attributes(x[[i]]) x[[i]] <- value attributes(x[[i]]) <- attrs x })(lst, "a", "z") str(res) #> List of 2 #> $ a: 'foo' chr "z" #> ..- attr(*, "type")= chr "bar" #> $ b: chr "y"
请问如何用Base R优雅实现该功能?我原本猜测可以实现[[<-.foo方法,但发现该方法针对的是foo类对象本身,而非列表中的foo元素,因此无法生效。仅接受Base R解决方案。
Base R解决方案
方案1:封装通用替换函数
把手动实现的逻辑封装成可复用函数,仅对foo类元素自动保留属性,其他元素正常赋值:
replace_keep_attrs <- function(x, i, value) { if ("foo" %in% class(x[[i]])) { attrs <- attributes(x[[i]]) x[[i]] <- value attributes(x[[i]]) <- attrs } else { x[[i]] <- value } x } # 使用示例 res <- replace_keep_attrs(lst, "a", "z") str(res) #> List of 2 #> $ a: 'foo' chr "z" #> ..- attr(*, "type")= chr "bar" #> $ b: chr "y"
方案2:自定义列表子类的赋值方法
如果想要更贴近原生赋值的体验,可以给列表创建一个子类,为其实现自定义的[[<-方法,自动处理foo类元素的属性保留:
# 给目标列表添加自定义子类 class(lst) <- c("foo_list", "list") # 实现自定义赋值方法 `[[<-.foo_list` <- function(x, i, value) { if ("foo" %in% class(x[[i]])) { attrs <- attributes(x[[i]]) NextMethod() # 执行默认的列表赋值逻辑 attributes(x[[i]]) <- attrs # 恢复原有属性 } else { NextMethod() # 非foo类元素正常赋值 } x } # 直接用原生赋值语法操作 lst[["a"]] <- "z" str(lst) #> List of 2 #> $ a: 'foo' chr "z" #> ..- attr(*, "type")= chr "bar" #> $ b: chr "y" #> - attr(*, "class")= chr [1:2] "foo_list" "list"
关于[[<-.foo方法的说明
你最初设想的[[<-.foo方法无法生效,因为[[<-操作的对象是列表而非foo类元素本身。[[<-.foo会被定义为操作foo类对象时的赋值方法,但这里我们的操作主体是列表,因此不会触发该方法。
内容的提问来源于stack exchange,提问作者Junitar
相关产品推荐
相关产品推荐

