1

So, I noticed that this question mentions one person's experience with [[ being faster than $ for list-element extraction, however I was wondering if anyone has a definite answer as of R version >= 3.0.2?

A colleague of mine has seen situations were $ is faster, yet this was sometime ago (and with Rcpp), and I'm wondering if anything has changed with R's evolution...

Community
  • 1
  • 1
StevieP
  • 1,569
  • 12
  • 23
  • possible duplicate of [R: Why is the \[\[ \]\] approach for subsetting a list faster than using $?](http://stackoverflow.com/questions/16630087/r-why-is-the-approach-for-subsetting-a-list-faster-than-using) – hrbrmstr Jul 29 '14 at 09:11
  • 2
    ...Is it truly a duplicate if I'm specifying for a more recent answer? – StevieP Jul 29 '14 at 11:07

2 Answers2

6

Just run some benchmarks for your case. Something like this:

mylist <- replicate(1e2, list(rnorm(1e3), sample(LETTERS, 1e2, TRUE)))
names(mylist) <- paste("X", seq_along(mylist))

library(rbenchmark)
benchmark(for (i in seq_len(1e4)) mylist$X1,
          for (i in seq_len(1e4)) mylist$"X1",
          for (i in seq_len(1e4)) mylist[["X1"]],
          for (i in seq_len(1e4)) mylist[["X1", exact = FALSE]],
          for (i in seq_len(1e4)) mylist[[1]],
          for (i in seq_len(1e4)) mylist$X50,
          for (i in seq_len(1e4)) mylist$"X50",
          for (i in seq_len(1e4)) mylist[["X50"]],
          for (i in seq_len(1e4)) mylist[["X50", exact = FALSE]],
          for (i in seq_len(1e4)) mylist[[50]],
          for (i in seq_len(1e4)) mylist$X100,
          for (i in seq_len(1e4)) mylist$"X100",
          for (i in seq_len(1e4)) mylist[["X100"]],
          for (i in seq_len(1e4)) mylist[["X100", exact = FALSE]],
          for (i in seq_len(1e4)) mylist[[100]],
          replications=100,
          columns=c('test', 'elapsed', 'replications', 'relative'),
          order='relative')

#                                                        test elapsed replications relative
#5                      for (i in seq_len(10000)) mylist[[1]]    0.20          100     1.00
#10                    for (i in seq_len(10000)) mylist[[50]]    0.22          100     1.10
#15                   for (i in seq_len(10000)) mylist[[100]]    0.22          100     1.10
#8                  for (i in seq_len(10000)) mylist[["X50"]]    2.76          100    13.80
#3                   for (i in seq_len(10000)) mylist[["X1"]]    2.87          100    14.35
#13                for (i in seq_len(10000)) mylist[["X100"]]    2.87          100    14.35
#6                       for (i in seq_len(10000)) mylist$X50    4.48          100    22.40
#7                       for (i in seq_len(10000)) mylist$X50    4.49          100    22.45
#12                     for (i in seq_len(10000)) mylist$X100    4.63          100    23.15
#1                        for (i in seq_len(10000)) mylist$X1    4.64          100    23.20
#2                        for (i in seq_len(10000)) mylist$X1    4.66          100    23.30
#11                     for (i in seq_len(10000)) mylist$X100    4.67          100    23.35
#9   for (i in seq_len(10000)) mylist[["X50", exact = FALSE]]    5.56          100    27.80
#4    for (i in seq_len(10000)) mylist[["X1", exact = FALSE]]    5.62          100    28.10
#14 for (i in seq_len(10000)) mylist[["X100", exact = FALSE]]    5.76          100    28.80

R.version
#platform       x86_64-w64-mingw32          
#arch           x86_64                      
#os             mingw32                     
#system         x86_64, mingw32             
#status                                     
#major          3                           
#minor          1.1                         
#year           2014                        
#month          07                          
#day            10                          
#svn rev        66115                       
#language       R                           
#version.string R version 3.1.1 (2014-07-10)
#nickname       Sock it to Me 
Roland
  • 127,288
  • 10
  • 191
  • 288
4

I think the linked Q&A should really answer this, but as with anything I guess the answer is, it depends. I think what is important is that [[ is designed to be as fast as possible, given the default, exact=TRUE and so should be the goto method unless you have a specific reason to do otherwise (others may disagree). Here are comments from the source code. The following are taking from /src/main/subset.c. Line numbers are given for reference:

[ subsetting:

  #635 /* The "[" subset operator.
  #636  * This provides the most general form of subsetting. */
  #637 
  #638 SEXP attribute_hidden do_subset(SEXP call, SEXP op, SEXP args, SEXP rho)
  #639 { ... }

[[ subsetting:

  #865 /* The [[ subset operator.  It needs to be fast. */
  #866 /* The arguments to this call are evaluated on entry. */
  #867 
  #868 SEXP attribute_hidden do_subset2(SEXP call, SEXP op, SEXP args, SEXP rho)
  #869 { ... }

$ subsetting:

 #1105 /* The $ subset operator.
 #1106    We need to be sure to only evaluate the first argument.
 #1107    The second will be a symbol that needs to be matched, not evaluated.
 #1108 */
 #1109 SEXP attribute_hidden do_subset3(SEXP call, SEXP op, SEXP args, SEXP env)
 #1110 { ... }
Simon O'Hanlon
  • 58,647
  • 14
  • 142
  • 184