I have a list called master
, which contains three IDs:
master = list(p1 = list(id = 'abc'), p2 = list(id = 'def'), p3 = list(id = 'ghi'))
str(master)
List of 3
$ p1:List of 1
..$ id: chr "abc"
$ p2:List of 1
..$ id: chr "def"
$ p3:List of 1
..$ id: chr "ghi"
To each level 1 element of this list, I would like to append the corresponding value and radius elements from the val
and rad
lists:
val = list(p1 = list(value = 5), p3 = list(value = 8))
str(val)
List of 2
$ p1:List of 1
..$ value: num 5
$ p3:List of 1
..$ value: num 8
rad = list(p1 = list(radius = 2), p2 = list(radius = 10))
str(rad)
List of 2
$ p1:List of 1
..$ radius: num 2
$ p2:List of 1
..$ radius: num 10
I have to be careful to match the elements by name because val
and rad
do not have the same structure as master
, i.e. val
is missing a slot for p2
and rad
is missing a slot for p3
.
I can use the following to partially achieve the desired result:
master_final = lapply(X=names(master),function(x, master, val, rad) c(master[[x]], val[[x]], rad[[x]]), master, val, rad)
str(master_final)
List of 3
$ :List of 3
..$ id : chr "abc"
..$ value : num 5
..$ radius: num 2
$ :List of 2
..$ id : chr "def"
..$ radius: num 10
$ :List of 2
..$ id : chr "ghi"
..$ value: num 8
But I would like each element of the resulting list to have the same structure, i.e. an id
, value
and radius
slot. I am not sure how to do this in a way that generalises to any number of lists? I don't like having to write [[x]]
for each list in the lapply
function: function(x, master, val, rad) c(master[[x]], val[[x]], rad[[x]])
.
One way would be to convert the lists to dataframe and do a merge
based on list name. We can then split
the dataframe based on list_name
.
df1 <- Reduce(function(x, y) merge(x, y, all = TRUE, by = "ind"),
list(stack(master), stack(val),stack(rad)))
names(df1) <- c("list_name", "id", "value", "radius")
lapply(split(df1[-1], df1$list_name), as.list)
#$p1
#$p1$id
#[1] "abc"
#$p1$value
#[1] 5
#$p1$radius
#[1] 2
#$p2
#$p2$id
#[1] "def"
#$p2$value
#[1] NA
#$p2$radius
#[1] 10
#$p3
#$p3$id
#[1] "ghi"
#$p3$value
#[1] 8
#$p3$radius
#[1] NA
This keeps NA
values in the list as it is, if we want to remove them the code becomes a bit ugly.
lapply(split(df1[-1], df1$list_name), function(x)
{inds <- !is.na(x); as.list(setNames(x[inds], names(x)[inds]))})
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