T-Wayne
T-Wayne

Reputation: 21

Rearranging an R list

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

Answers (3)

Rich Scriven
Rich Scriven

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

IRTFM
IRTFM

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

A5C1D2H2I1M1N2O1R2T1
A5C1D2H2I1M1N2O1R2T1

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

Related Questions