I want to assign the same value to specific elements in nested lists that have the same name. I would also like to create the element if it didn't exist in the nested list, but this isn't shown in my example.
For example, let's say I have:
ls <- list(a = list(e1 = "value1.1", e2 = "value1.2"),
b = list(e1 = "value2.1", e2 = "value2.2"))
And I want to assign the value "same value" to all the elements in sublists that are named e1
so that I would end up with this desired output:
list(a = list(e1 = "same value", e2 = "value1.2"),
b = list(e1 = "same value", e2 = "value2.2")
> ls
$a
$a$e1
[1] "same value"
$a$e2
[1] "value1.2"
$b
$b$e1
[1] "same value"
$b$e2
[1] "value2.2"
After researches, I found the function modify_depth()
in the package purrr
that will apply a function to the nested lists, but won't assign a value.
My only other solution was to do this:
ls2 <- list()
for(sublist in ls){
sublist[["e1"]] <- "same value"
ls2 <- c(ls2, list(sublist))
}
names(ls2) <- names(ls)
ls <- ls2
rm(ls2)
Note: after the loop, "same value" are not assigned in ls, so I have to create ls2
. I could make this a function, but I'm sure there is a better way to do this, without a for
loop.
Thanks for your help!
With map
and replace
from purrr
:
library(purrr)
map(ls, ~replace(., "e1", "same value"))
or with modify_depth
:
modify_depth(ls, 1, ~replace(., "e1", "same value"))
replace
also works with lapply
:
lapply(ls, replace, "e1", "same value")
Output:
$a
$a$e1
[1] "same value"
$a$e2
[1] "value1.2"
$b
$b$e1
[1] "same value"
$b$e2
[1] "value2.2"
The good thing about modify_depth
is that you can choose the depth, whereas map
and lapply
only goes down one level:
ls2 <- list(c = list(a1 = list(e1 = "value1.1", e2 = "value1.2")),
d = list(a1 = list(e1 = "value2.1", e2 = "value2.2")))
modify_depth(ls2, 2, ~replace(., "e1", "same value"))
Output:
$c
$c$a1
$c$a1$e1
[1] "same value"
$c$a1$e2
[1] "value1.2"
$d
$d$a1
$d$a1$e1
[1] "same value"
$d$a1$e2
[1] "value2.2"
Edit: If we want to apply a vector of values to each e1
element of ls2
, modify_depth
would not work since it does not have a map2
variant. Instead, I would use two layers of map
's, map2
on the top layer, and map
on the second layer.
vec <- c("newvalue1.1", "newvalue2.1")
map2(ls2, vec, ~map(.x, replace, "e1", .y))
Output:
$c
$c$a1
$c$a1$e1
[1] "newvalue1.1"
$c$a1$e2
[1] "value1.2"
$d
$d$a1
$d$a1$e1
[1] "newvalue2.1"
$d$a1$e2
[1] "value2.2"
We can use lapply
to iterate over list elements, then using [
with logical operator for equality ==
we can locate the values we want to change
> lapply(ls, function(x){
x[names(x)=="e1"] <- "same.value"
x
} )
$`a`
$`a`$`e1`
[1] "same.value"
$`a`$e2
[1] "value1.2"
$b
$b$`e1`
[1] "same.value"
$b$e2
[1] "value2.2"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With