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?
1 Like
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
5 Likes
cole
April 9, 2019, 3:23am
5
Just for the sake of completeness, have a look at
library(purrr)
list_merge
list_modify
update_list
They changed my life
1 Like
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
rensa
April 9, 2019, 1:42pm
7
Not quite what you were looking for, but it's also useful to know that purrr::pluck()
recently received a replacement function variant
pluck(original, 'x') <- 2
2 Likes
It never occured to me that you could set your own assignment functions
x = .x,
index = list2(...),
missing = NULL,
strict = TRUE
)
}
#' @rdname pluck
#' @inheritParams modify_in
#' @export
`pluck<-` <- function(.x, ..., value) {
assign_in(.x, list2(...), value)
}
reduce_subset_call <- function(init, idx) {
if (!length(idx)) {
abort("Can't pluck-assign without pluck locations")
}
reduce(idx, subset_call, .init = init)
}
subset_call <- function(x, idx) {
Thanks, Rensa!
2 Likes
system
Closed
April 16, 2019, 2:20pm
9
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.