I have the following list that I wish to unpack (aka expand) using only base R.
For example, I want to turn this:
b <- list(a = c(1, 2), b = 1, d = c(5, 7))
into the equivalent of:
list(a = 1, a = 2, b = 1, d = 5, d = 7)
I have this function that works if only one named element has length > 1 but not if there are multiple elements:
expand_list <- function(listx){
long_elements <- as.numeric(which(lapply(listx, length) > 1))
short_elements <- as.numeric(which(lapply(listx, length) == 1))
res <- lapply(long_elements, function(x){
as.list(setNames(listx[[x]], rep(names(listx)[x], length(listx[[x]]))))
})
expanded_elements <- res[[1]]
c(listx[short_elements], expanded_elements)
}
expand_list(b)
You can use stack followed by setNames to achieve that
y <- list(a = c(1, 2), b = 1, c = 2, d = c(5, 7))
x <- stack(y)
as.list(setNames(x$values, x$ind))
Related
TLDR:
I need a simple way to transform c(a = 1, a = 3, a = 6) into list(c(a = 1), c(a = 3), c(a = 6)).
Longer version:
I am using the function purrr::accumulate(), where the output of each element is an atomic vector of length greater or equal to one. When the length is one, purrr::accumulate() simplifies the whole output to an atomic vector, instead of a list.
Is there a simple way to undo or avoid this? Unfortunately, as.list() does not give me what I want.
Simple example to illustrate:
purrr::accumulate(2:3, `+`, .init = c(a=1, b=2))
gives me
list(c(a = 1, b = 2), c(a = 3, b = 4), c(a = 6, b = 7))
as expected. However,
purrr::accumulate(2:3, `+`, .init = c(a=1))
gives me
c(a = 1, a = 3, a = 6)
when I instead want
list(c(a = 1), c(a = 3), c(a = 6))
You could try
c(a = 1, a = 3, a = 6) %>% map(~setNames(.x, nm = "a"))
$a
a
1
$a
a
3
$a
a
6
or you can also remove the list names with set_names()
c(a = 1, a = 3, a = 6) %>% map(~setNames(.x, nm = "a")) %>%
set_names("")
[[1]]
a
1
[[2]]
a
3
[[3]]
a
6
I have a list of list like ll:
ll <- list(a = list(data.frame(c = 1, d = 2), data.frame(h = 3, j = 4)), b = list(data.frame(c = 5, d = 6), data.frame(h = 7, j = 9)))
I want to unnest/unlist the last level of the structure (the interior list). Note that every list contains the same structure. I want to obtain lj:
lj <- list(a = (data.frame(c = 1, d = 2, h = 3, j = 4)), b = data.frame(c = 5, d = 6, h = 7, j = 9))
I have tried the following code without any success:
lj_not_success <- unlist(ll, recursive = F)
However, this code unlists the FIRST level, not the LAST one.
Any clue?
We may need to cbind the inner list elements instead of unlisting as the expected output is a also a list of data.frames
ll_new <- lapply(ll, function(x) do.call(cbind, x))
-checking
> identical(lj, ll_new)
[1] TRUE
I have some R-function f, which fixes some parameters of some other function target (thanks to GKi for help):
target <- function(b1,b2,l1,l2,l3,o1,o2) return((b1+b2+l1+l2+l3+o1+o2)^2)
fixed <- c(b1 = 1, l1 = 2, l2 = 3, l3 = 4, o1 = 5)
variable <- c("o2","b2")
f <- function(fixed, variable) {
target_new <- function() {}
formals(target_new) <- setNames(rep(list(bquote()), length(variable)), variable)
for(i in variable) assign(i, as.symbol(i))
body(target_new) <- do.call("call", unlist(list("target", mget(variable), as.list(fixed))))
return(target_new)
}
f(fixed,variable)
> function (o2, b2)
> target(o2 = o2, b2 = b2, b1 = 1, l1 = 2, l2 = 3, l3 = 4, o1 = 5)
> <environment: 0x0000020a8e0c0c88>
I want to maximize target_new by nlm, so I need to concentrate its function arguments into a vector, i.e. the desired output of f(fixed,variable) is
> function (theta)
> target(o2 = theta[1], b2 = theta[2], b1 = 1, l1 = 2, l2 = 3, l3 = 4, o1 = 5)
How to modify the above code, so that the function can process the vector theta?
Please mind that the vectors fixed and variable can be of variable lengths.
You are making this too complicated.
f <- function(fixed, variable) {
function(theta) {
args <- c(as.list(theta), as.list(fixed))
names(args)[seq_along(variable)] <- variable
do.call(target, args)
}
}
fun <- f(fixed, variable)
#does it work?
all.equal(
nlm(fun, p = c(1, 2)),
nlm(function(theta) target(1,theta[2], 2, 3, 4, 5, theta[1]),
p = c(1, 2))
)
#[1] TRUE
I have list out like this:
u <- list(a = list(b = 1, c = 2),
x = list(k = list(ka = 1, kb = 3),
l = list(la = 1, la = 4)))
v <- list(a = list(b = 1, c = 2),
x = list(m = list(ma = 5, mb = 8),
n = list(na = 5, nb = 8)))
w <- list(a = list(b = 1, c = 2),
x = list(o = list(oa = 4, ob = 1),
p = list(pa = 8, pb = 0)))
out <- list(u, v, w)
I would like to create another list where there are elements k, l, m, n, o, p and names of the list elements are preserved. I found a solution, but looks sub-optimal:
x <- lapply(out, function(y) y[['x']])
o <- list()
for (a in x) {
o <- c(o, a)
}
> str(o, max.level = 1)
List of 6
$ k:List of 2
$ l:List of 2
$ m:List of 2
$ n:List of 2
$ o:List of 2
$ p:List of 2
Is there a better way?
The loop could be replaced with unlist:
res <- unlist( lapply(out,"[[","x"), recursive=FALSE)
identical(res,o)
# [1] TRUE
My lapply is the same as in the OP; it's just a shortcut.
As #akrun suggested, you could more closely mirror the OP's loop with
do.call("c", lapply(out, '[[', 'x'))
I have two lists v and w and I would like to create again a list z from matrix M . How can I do this in R?
v = list(a = c(1, 5), b = 2, c= 3)
w = list( a= c(2, 10), b = 4, c = 6)
M = as.matrix(unlist( v) * unlist(w))
> M
[,1]
a1 2
a2 50
b 8
c 18
z = list(a = c(2, 50), b = 8, c = 18)
Do it like this:
mapply(`*`, v, w)
Maybe you want z <- lapply(1:length(v), function(i) v[[i]]*w[[i]])? Add names(z) <- names(v) to keep the names.