26

I'd like to know how I can iterate over a key/value pair from a list object in R, like the example below:

toto <- list(a="my name is",b="I'm called",c="name:")
myfun <- function(key,value) paste(value,key)
for( key in names(toto) ) toto[key] <- myfun(key,toto[[key]])

Is there a way to avoid the for loop (using lapply() or such). Would it be faster?

Thanks!

caas
  • 455
  • 1
  • 5
  • 12
  • 3
    Just keep in mind that `lapply` still involves iteration, and while it is likely a little faster than `for`, this isn't always the case (and it certainly isn't equivalent to vectorizing the function). http://stackoverflow.com/questions/2275896/is-rs-apply-family-more-than-syntactic-sugar/2276001#2276001 – Shane Dec 21 '10 at 14:27

3 Answers3

23

The R folks often don't like to give a straight answer to a simple question.

This is how you can iterate over key/value pairs in a list:

for (name in names(myList)) {
  print(name)
  print(myList[[name]])
}
Max
  • 1,135
  • 13
  • 15
21

The best solution of all is to simply call paste directly without a loop (it's vectorized already):

> paste(toto, names(toto))
[1] "my name is a" "I'm called b" "name: c"  

A similar question previously asked on R-Help, with several creative solutions. lapply cannot show the names within the function. This function was provided by Romain Francois based on something by Thomas Lumley:

yapply <- function(X,FUN, ...) { 
  index <- seq(length.out=length(X)) 
  namesX <- names(X) 
  if(is.null(namesX)) 
    namesX <- rep(NA,length(X))

  FUN <- match.fun(FUN) 
  fnames <- names(formals(FUN)) 
  if( ! "INDEX" %in% fnames ){ 
    formals(FUN) <- append( formals(FUN), alist(INDEX=) )   
  } 
  if( ! "NAMES" %in% fnames ){ 
    formals(FUN) <- append( formals(FUN), alist(NAMES=) )   
  } 
  mapply(FUN,X,INDEX=index, NAMES=namesX,MoreArgs=list(...)) 
}

Here's an example of usage:

> yapply(toto, function( x ) paste(x, NAMES) )
             a              b              c 
"my name is a" "I'm called b"      "name: c" 
Shane
  • 98,550
  • 35
  • 224
  • 217
  • 10
    And basic use of `mapply` to OP case will be `mapply(myfun, key=names(toto), value=toto)`. – Marek Dec 21 '10 at 14:37
  • 1
    @Marek Good point! I did think it worth covering more than just paste in case the OP had other usages in mind with the question. I would also note that this is essentially what `yapply` does behind the scenes (see the last line of that function). – Shane Dec 21 '10 at 16:01
  • 1
    i would prefer `mapply` any day to `yapply` so that any decent R programmer can easily understand what you are doing since it is a "standard" apply function anyway. – Aizzat Suhardi Jul 13 '15 at 17:13
5

This should do it for you:

do.call(paste, list(toto, names(toto) ))
Prasad Chalasani
  • 19,912
  • 7
  • 51
  • 73
  • 8
    no need for do.call here. paste(toto,names(toto)) works just as fine. And is in my eyes even more elegant. – Joris Meys Dec 21 '10 at 14:33