Reputation: 21
Suppose I have a list structured as such.
list(
a = list(
a1 = c(1, 2),
b1 = c(2, 3)
),
b = list(
a1 = c(3, 4),
b1 = c(4, 5)
)
)
What clever use of core R functions, without apply's or recursive functions, can I use to transform it to the following?
list(
a1 = list(
a = c(1, 2),
b = c(3, 4)
),
b1 = list(
a = c(2, 3),
b = c(4, 5)
)
)
Using stack() drops the inner indices. Using unlist() merges both indices together.
Upvotes: 0
Views: 147
Reputation: 99331
You could take advantage of the fact that the list is an environment
, and use within
.
x
is the list.
> within(x, { a$b1 <- b$a1; b$a1 <- a$b1-1 })
$a
$a$a1
[1] 1 2
$a$b1
[1] 3 4
$b
$b$a1
[1] 2 3
$b$b1
[1] 4 5
Here are some other things that might be of interest Not sure why people seem to steer away from the base R funcions. They are very useful in these types of problems (and they make all of Ananda's loops work ;-).
Did everyone forget about recursive concatenation...
> str(x)
List of 2
$ a:List of 2
..$ a1: num [1:2] 1 2
..$ b1: num [1:2] 2 3
$ b:List of 2
..$ a1: num [1:2] 3 4
..$ b1: num [1:2] 4 5
From str(x)
alone, you can plan the route down the list. In your list, it's a [2:1][1:2]
reversal. By the way R is vectorized!
These things are also useful..
> do.call("names", list(c(x)))
#[1] "a" "b"
> do.call("names", list(c(x,recursive=TRUE)))
#[1] "a.a11" "a.a12" "a.b11" "a.b12" "b.a11" "b.a12" "b.b11" "b.b12"
> do.call("c", list(c(x,recursive=TRUE)))
#a.a11 a.a12 a.b11 a.b12 b.a11 b.a12 b.b11 b.b12
# 1 2 2 3 3 4 4 5
> do.call("c", list(c(x,recursive=TRUE,use.names=FALSE)))
#[1] 1 2 2 3 3 4 4 5
> do.call("as.expression", list(c(x)))
# expression(a = list(a1 = c(1, 2), b1 = c(2, 3)), b = list(a1 = c(3, 4), b1 = c(4, 5)))
> do.call("as.expression", list(c(x,recursive=TRUE)))
# expression(1, 2, 2, 3, 3, 4, 4, 5)
You'll want to do some kind of recursion, the .Primitive
functions are coded entirely in C and they're not slow by any means.
Here I'm at ground level with the vectors you want to change.
> c(x,recursive=TRUE)[3:6]
# a.b11 a.b12 b.a11 b.a12
# 2 3 3 4
Upvotes: 1
Reputation: 263311
m <- do.call(rbind, ll) ;m2 <- split(m, col(m)) # that transposes the data
names(m2) <- names(ll[[1]]) # these two steps "transpose" the names
lapply(m2, setNames, names(ll) )
$a1
$a1$a
[1] 1 2
$a1$b
[1] 3 4
$b1
$b1$a
[1] 2 3
$b1$b
[1] 4 5
Upvotes: 0
Reputation: 193517
OK. Here's an attempt:
L1 <- stack(unlist(L, recursive = FALSE))
L2 <- cbind(L1, do.call(rbind, strsplit(
as.character(L1$ind), ".", fixed = TRUE)))
c(by(L2[c("values", "1")], L2[["2"]],
FUN = function(x) split(x[["values"]], x[["1"]])))
# $a1
# $a1$a
# [1] 1 2
#
# $a1$b
# [1] 3 4
#
#
# $b1
# $b1$a
# [1] 2 3
#
# $b1$b
# [1] 4 5
I've wrapped the output of by
with c
to remove the by
-related attributes
and return the output to a basic list
.
Upvotes: 2