[R] name returned by lapply

Gavin Simpson gavin.simpson at ucl.ac.uk
Fri Jul 18 14:39:10 CEST 2008


On Fri, 2008-07-18 at 14:19 +0200, Antje wrote:
> Hi Gavin,
> 
> thanks a lot for your answer.
> Maybe I did not explain very well what I want to do and probably chose a bad 
> example. I don't mind spaces or names starting with a number. I could even name it:
> 
> "Hugo1", "Hugo2", ...
> 
> My biggest problem is, that not only the values are calculated/estimated within 
> my function but also the names (Yes, in reality my funtion is more complicated).
> Maybe it's easier to explain like this. the parameter x can be a coordinate 
> position of mountains on earth. Within the funtion the height of the mountain 
> is estimated and it's name.
> In the end, I'd like to get a list, where the entry is named like the mountain 
> and it contains its height (or other measurements...)
> 
> 
> > ## now that we have a list, we change the names to what you want
> > names(ret) <- paste(1:10, "info_within_function")
> 
> so this would not work, because I don't have the information anymore about the 
> naming...

OK, so you can't do what you want to do in the manner you tried, via
lapply as you don't have control of how the list is produced once the
loop over 1:10 has been performed. At the stage that 'test' is being
applied, all it knows about is 'x' and it doesn;t have access to the
list being built up by lapply().

The *apply family of functions help us to *not* write out formal loops
in R, but here this is causing you a problem. So we can specify an
explicit loop and fill in information as and when we want from within
the loop

## create list to hold results
n <- 10
ret <- vector(mode = "list", length = n)
## initialise loop
for(i in seq_len(n)) {
    ## do whatever you need to do here, but this line just
    ## replicates what 'test' did earlier
    ret[[i]] <- c(1,2,3,4,5)
    ## now add the name in
    names(ret)[i] <- paste("Mountain", i, sep = "")
}
ret

Alternatively, collect a vector of names during the loop and then once
the loop is finished do a single call to names(ret) to replace all the
names at once:

n <- 10
ret <- vector(mode = "list", length = n)
## new vector to hold vector of names
name.vec <- character(n)
for(i in seq_len(n)) {
    ret[[i]] <- c(1,2,3,4,5)
    ## now we just fill in this vector as we go
    name.vec[i] <- paste("Mountain", i, sep = "")
}
## now replace all the names at once
names(ret) <- name.vec
ret

This latter version is likely to more efficient if n is big so you don't
incur the overhead of the repeated calls to names()

The moral of the story is to not jump to using *apply all the time to
avoid loops. Loops in R are just fine, so use the tool that helps you do
the job most efficiently *and* most transparently.

Take a look at the R Help Desk article by Uwe Ligges and John Fox in the
current issue of RNews:

http://www.r-project.org/doc/Rnews/Rnews_2008-1.pdf

Which goes into this in much more detail

HTH

G

-- 
%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%
 Dr. Gavin Simpson             [t] +44 (0)20 7679 0522
 ECRC, UCL Geography,          [f] +44 (0)20 7679 0565
 Pearson Building,             [e] gavin.simpsonATNOSPAMucl.ac.uk
 Gower Street, London          [w] http://www.ucl.ac.uk/~ucfagls/
 UK. WC1E 6BT.                 [w] http://www.freshwaters.org.uk
%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%



More information about the R-help mailing list