3

Is there a way I can make an lapply statement also show the index? More specifically, consider the following example:

mylist <- list(c(5,4),c(3,2), c(1,3))

myfunction<- function(values){
  print("Adding values: ")
  return(values[1] + values[2])
}

lapply(mylist, myfunction)

Is there a way I can somehow make it print "Adding Values: 1" "Adding Values: 2" etc.. one element of each in the list?

Thanks!

user1357015
  • 11,168
  • 22
  • 66
  • 111
  • 1
    Well, you could have `myfunction` take an index instead of a list item, do `print(idx)`, get the value with `values = mylist[[idx]`, and do `lapply(1:length(mylist), myfunction)` – David Robinson Sep 10 '12 at 03:22
  • sorry, but I'm not sure how that would quite work? In this case myfunction just gets a number, I need it to get a bunch of things. Perhaps you can provide some more pseudocode? Apologies for the confusion! – user1357015 Sep 10 '12 at 03:29
  • See `?lapply` and read the explanation of the arguments. Note that `...` is used for additional arguments to your function, so you'd specify them there. – joran Sep 10 '12 at 03:31

3 Answers3

14

The function mapply works like lapply but allows you to supply multiple vectors or lists.

In your case you can create a second vector, the same length of the list, just counting up:

mapply(myfunction, mylist, seq_along(mylist))

Let's try it:

myfunction<- function(values, index){ 
  cat("Adding values (", index, "): ", values[1], "...", values[2], " = ", sum(values), "\n" )
  invisible(values[1] + values[2])
}

mylist <- list(c(5, 4), c(3, 2), c(1, 3))

mapply(myfunction, mylist, seq_along(mylist))

Result:

Adding values ( 1 ):  5 ... 4  =  9 
Adding values ( 2 ):  3 ... 2  =  5 
Adding values ( 3 ):  1 ... 3  =  4 

Advanced user fun

Just for fun, a careful reading of the ?lapply manual page reveals that the following also works:

myfunction<- function(values){
    print(sprintf("Adding values: %i",substitute(values)[[3]]))
    return(values[1] + values[2])
}

lapply(mylist, myfunction)

Which suggests a general function adaptor could be created to supply index to your original function (or any other), modified to expect a second index argument:

myfunction<- function(values,index){
    print(sprintf("Adding values: %i",index))
    return(values[1] + values[2])
}

Now the adaptor

lapply_index_adaptor=function(f)function(x,...)f(x,substitute(x)[[3]],...)

and now the lapply call, with the adaptor:

lapply(mylist, lapply_index_adaptor(myfunction))
Alex Brown
  • 41,819
  • 10
  • 94
  • 108
7

It is good to use message if you mean a message.

mylist <- list(c(5, 4), c(3, 2), c(1, 3))

If you want the index (on rereading this may be what you want)

myfunction_idx <- function(idx, x) {
    .x <- x[[idx]]
    message(sprintf("Adding values %s:", idx))

    sum(.x)
}
lapply(seq_along(mylist), myfunction_idx, x = mylist)

## Adding values 1: 

## Adding values 2: 

## Adding values 3: 

## [[1]]
## [1] 9
## 
## [[2]]
## [1] 5
## 
## [[3]]
## [1] 4
## 

plyr solution

The plyr package will construct a progress bar on the fly (lapply will be quicker

library(plyr)
llply(mylist, sum, .progress = 'text')
mnel
  • 113,303
  • 27
  • 265
  • 254
  • No, this is not quite it. My own example is much more complicated. I can't put in a cat message of what's the input to myfuction as that won't be helpful to the user. Each list element has itself a lot of subelements that are used. I specifically want it to print "Processing List Element 1", "Processing List Element 2", etc.... This way the user knows how far it is in the lapply. Thanks! – user1357015 Sep 10 '12 at 03:28
  • I've edited the response. Is this more what you want? – mnel Sep 10 '12 at 03:34
  • Not quite, but this is really neat! Thanks for showing me llply! – user1357015 Sep 10 '12 at 04:33
2

Are you asking for 'commentary' on the particular values and process that is happening?

myfunction<- function(values){ 
  cat("Adding values: ", values[1], "...", values[2], " = ", sum(values), "\n" )
  invisible(values[1] + values[2])
}

 lapply(mylist, myfunction)

Adding values:  5 ... 4  =  9 
Adding values:  3 ... 2  =  5 
Adding values:  1 ... 3  =  4 
[[1]]
[1] 9

[[2]]
[1] 5

[[3]]
[1] 4
IRTFM
  • 258,963
  • 21
  • 364
  • 487