sds
sds

Reputation: 60004

Is it possible to modify list elements?

I have a list of records:

z <- list(list(a=1),list(a=4),list(a=2))

and I try to add fields to each of them. Alas, neither

lapply(z,function(l) l$b <- 1+l$a)

nor

for(l in z) l$b <- 1+l$a

modifies z.

In this simple case I can, of course, do

z <- lapply(z,function(l) c(list(b= 1+l$a),l))

but this quickly gets out of hand when the lists have more nesting:

z <- list(list(a=list(b=1)),list(a=list(b=4)),list(a=list(b=2)))

How do I turn it into

list(list(a=list(b=1,c=2)),list(a=list(b=4,c=5)),list(a=list(b=2,c=3)))

without repeating the definition of the whole structure? Each element of z has many fields, not just a; and z[[10]]$a has many subfields, not just b.

Upvotes: 4

Views: 2621

Answers (2)

josliber
josliber

Reputation: 44309

Your first code example doesn't modify the list because you need to return the list in your call to lapply:

z <- list(list(a=1),list(a=4),list(a=2))
expected <- list(list(a=1, b=2), list(a=4, b=5), list(a=2, b=3))
outcome <- lapply(z,function(l) {l$b <- 1+l$a ; l})
all.equal(expected, outcome)
# [1] TRUE

In the doubly nested example, you could use lapply within lapply, again making sure to return the list in the inner lapply:

z <- list(list(a=list(b=1)),list(a=list(b=4)),list(a=list(b=2)))
expected <- list(list(a=list(b=1, c=2)), list(a=list(b=4, c=5)), list(a=list(b=2, c=3)))
obtained <- lapply(z, function(l1) { lapply(l1, function(l2) {l2$c = l2$b+1 ; l2 } )})
all.equal(expected, obtained)
# [1] TRUE

Upvotes: 4

joran
joran

Reputation: 173547

Another, somewhat convoluted, option:

z <- list(list(a=1),list(a=4),list(a=2))
res <- list(list(a=list(b=1,c=2)),list(a=list(b=4,c=5)),list(a=list(b=2,c=3)))
res1 <- rapply(z,function(x) list(b = x,c = x+1),how = "replace")
> all.equal(res,res1)
[1] TRUE

I only say convoluted because rapply can be tricky to use at times (for me at least).

Upvotes: 2

Related Questions