3

I was working with a list of lists today and needed to replace an element of one of the second-level lists. The way to do this seemed obvious, but I realized I wasn't actually clear on why it worked.

Here's an example:

a <- list(aa=list(aaa=1:10,bbb=11:20,ccc=21:30),bb=list(ddd=1:5))

Given this data structure, let's say I want to replace the 3rd element of the nested numeric vector aaa. I could do something like:

newvalue <- 100
a$aa$aaa[3] <- newvalue

Doing this seems obvious enough, but I couldn't explain to myself how this expression actually gets evaluated. Working with the quote function, I cobbled together some rough logic, along the lines of:

(1) Create and submit the top-level function call:

`<-`(a$aa$aaa[3],newvalue)  

(2) Lazy evaluation of first argument in (1), call function '[':

`[`(a$aa$aaa,3)    

(3) Proceed recursivley down:

`$`(a$aa,"aaa")

(4) ...further down, call '$' again:

`$`(a,"aa")

(5) With (4) returning an actual data structure, proceed back "up the stack" substituting the returned data structures until the actual assignment is made in (1).

I guess my confusion involves some aspects of lazy evaluation and/or evaluation environments. In the example above, I've simply reassigned one element of a vector. But how is it that R keeps track of where that vector is within the greater data structure?

Cheers

Al R.
  • 2,430
  • 4
  • 28
  • 40
  • 2
    I wonder if this [Answer](http://stackoverflow.com/questions/6437769/why-does-item-assignment-in-non-existant-data-frame-column-work/6440706#6440706) might help? – Gavin Simpson Oct 19 '11 at 18:41

1 Answers1

1

I think a$aa$aaa[3] works as followed:

When you want to access an element still within the current object you use single square brackets, []. This makes the element accesible, but you can not perform complex manipulations with it because the element is still part of the object.

When you access the element using $, this translates from a$aa to a[["aa"]], thus releasing the element from the current object.

The total expression a$aa$aaa[3] translates to a[["aa"]][["aaa"]][3]. This is treated as a vector of vectors ->

  1. Take object a, access vector aa.
  2. Access vector aaa.
  3. Access the third element in vector aaa.

The R evaluation:

 > a
 $aa
 $aa$aaa
 [1]  1  2  3  4  5  6  7  8  9 10

 $aa$bbb
 [1] 11 12 13 14 15 16 17 18 19 20

 $aa$ccc
 [1] 21 22 23 24 25 26 27 28 29 30


 $bb
 $bb$ddd
 [1] 1 2 3 4 5


 > a$aa
 $aaa
 [1]  1  2  3  4  5  6  7  8  9 10

 $bbb
 [1] 11 12 13 14 15 16 17 18 19 20

 $ccc
 [1] 21 22 23 24 25 26 27 28 29 30

 > a$aa$aaa
 [1]  1  2  3  4  5  6  7  8  9 10
 > a[["aa"]]
 $aaa
 [1]  1  2  3  4  5  6  7  8  9 10

 $bbb
 [1] 11 12 13 14 15 16 17 18 19 20

 $ccc
 [1] 21 22 23 24 25 26 27 28 29 30

 > a[["aa"]][["aaa"]]
 [1]  1  2  3  4  5  6  7  8  9 10
 > a["aa"]
 $aa
 $aa$aaa
 [1]  1  2  3  4  5  6  7  8  9 10

 $aa$bbb
 [1] 11 12 13 14 15 16 17 18 19 20

 $aa$ccc
 [1] 21 22 23 24 25 26 27 28 29 30


 > a["aa"]["aaa"]
 $<NA>
 NULL

Hope this helps.

Mischa Vreeburg
  • 1,576
  • 1
  • 13
  • 18