rr-s3

Replacing list elements while preserving their attributes


Consider the following list:

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"

Created on 2024-03-01 with reprex v2.1.0

I would like to preserve the attributes when replacing elements of class foo with another value. Basically I'd like a method that replicates the following behavior:

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"

Created on 2024-03-01 with reprex v2.1.0

How can I do that? I guess the solution is to implement a `[[<-.foo` method but can't figure out how to make it work? As far as I understand this kind of method will use the class of lst, not that of the elements it contains.

I'm looking for a base R solution only.


Solution

  • The value of lst[["a"]] can be changed, while keeping its attributes using lst[["a"]][] <- "z".

    #Example data
    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"
    
    #Change element a, while keeping attributes
    lst[["a"]][] <- "z"
    str(lst)
    #List of 2
    # $ a: 'foo' chr "z"
    #  ..- attr(*, "type")= chr "bar"
    # $ b: chr "y"