Update a set of list values

I want a function that allows me to update a value (by name) within a list. I was imagining something like some_function here:

original <- list(x = 1, y = 2)

some_function(original, x = 2)
#> $x
#> [1] 2
#> 
#> $y
#> [1] 2

Does a function that does this already exist? It feels like there probably is something in base but I haven't been able to find it.

Or, is there an alternative data structure that it better suited to this? Something more like a map or dict?

For a single key-value pair, this can be done pretty trivially with [<-:

`[<-`(original, "x", 2)
#> $x
#> [1] 2
#> 
#> $x
#> [1] 1

And so you could write a function that does this for a series of key-value pairs (e.g. with reduce). However, it still feels like this is a bit involved for quite simple functionality that probably exists within the language anyway.


As a semi-interesting sidebar, I thought I could easily achieve something similar with append or rlang::list2, but apparently I misunderstood some of R's list semantics:

update_list_rlang <- function(original, ...) {
  rlang::list2(..., !!!original)
}
update_list_rlang(original, x = 2)
#> $x
#> [1] 2
#> 
#> $x
#> [1] 1
#> 
#> $y
#> [1] 2

append(original, list(x = 2))
#> $x
#> [1] 1
#> 
#> $y
#> [1] 2
#> 
#> $x
#> [1] 2

Upon inspection, this makes sense, but I was initially surprised to see that multiple list elements could have the same name.

It seems that [<- can take vector arguments, which solves the problem:

original <- list(x = 1, y = 2)

update_list <- function(original, ...) {
  edits <- list(...)
  `[<-`(original, names(edits), edits)
}

update_list(original, x = 2)
#> $x
#> [1] 2
#> 
#> $y
#> [1] 2

update_list(original, x = 3, z = 1)
#> $x
#> [1] 3
#> 
#> $y
#> [1] 2
#> 
#> $z
#> [1] 1

However, even better than this, is utils::modifyList, which does exactly what I was looking for:

modifyList(original, list(x = 2))
#> $x
#> [1] 2
#> 
#> $y
#> [1] 2
4 Likes

Just for the sake of completeness, have a look at

library(purrr)
list_merge
list_modify
update_list

They changed my life :slight_smile:

Ah yes, I should have thought to look in purrr! I ended up looking in rlang for some reason (I suppose I thought that this was very low-level functionality?).

Thank you, Cole

1 Like

Not quite what you were looking for, but it's also useful to know that purrr::pluck() recently received a replacement function variant :slightly_smiling_face:

pluck(original, 'x') <- 2
2 Likes

It never occured to me that you could set your own assignment functions :exploding_head:

Thanks, Rensa!

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.