2

I'd like to pass a data frame into lapply via %>%, but I need to be able to access the names of the columns, so my lapply arguments are something like this:

mydf %>%
   lapply( 1:length(.), function(x) {
        manipulate_df( mydf[x], using_column_names(names(mydf)[x] )
   })

However, when I try that, I get the following error:

Error in match.fun(FUN) :
   '1:length(.)' is not a function, character or symbol

As far as I can tell R and lapply don't like 1:length(.). I suppose a valid option is breaking the chain, but I'd like to learn how to do it properly.

crazybilly
  • 2,992
  • 1
  • 16
  • 42
  • 2
    You may want to read `help("%>%")`. It's not that `lapply()` "doesn't like" `1:length(.)`. You've already passed `X` to `lapply()` via `%>%`. It's `mydf`. IMO, it would be better to call `lapply()` in the standard manner here (i.e. without the chain). – Rich Scriven Jun 07 '16 at 16:53

3 Answers3

2

Your issue here is that %>% is inserting mydf as the first argument (so that three arguments are getting passed to lapply. Try wrapping the entire lapply expression in brackets. This prevents the insertion behavior:

mydf %>%
   { lapply( 1:length(.), function(x) {
        manipulate_df( mydf[x], using_column_names(names(mydf)[x] )
   }) }

I think the prettiest fix would be to make a new function:

manipulate_whole_df = function(mydf)
  lapply( 1:length(mydf), function(x)
            manipulate_df( mydf[x], using_column_names(names(mydf)[x] ) ) )

mydf %>%
  manipulate_whole_df

Or even

library(tidyr)

mydf %>%
  gather(variable, value) %>%
  group_by(variable) %>%
  do(manipulate_df(.$value, 
                   .$variable %>% first %>% using_column_name ) )
bramtayl
  • 4,004
  • 2
  • 11
  • 18
0

The function in lapply() only references the column indexes / column names, referencing mtcars in a way that does not depend on the iteration in lapply, so pipe the names

names(mtcars) %>% lapply(function(x) mtcars[x])

or write a proper closure

names(mtcars) %>% lapply(function(x, df) df[x], df=mtcars)

or perhaps you don't really need to access the names but just the columns?

mtcars %>% lapply(function(x) sqrt(sum(x)))
Martin Morgan
  • 45,935
  • 7
  • 84
  • 112
0

I think what you want is the following:

mydf %>% length %>% seq %>%
   lapply(function(x) {
        manipulate_df( mydf[x], using_column_names(names(mydf)[x] )
   })

or you can use a lambda function:

mydf %>% {1:length(.)} %>%
   lapply(function(x) {
        manipulate_df( mydf[x], using_column_names(names(mydf)[x] )
   })
f.jamitzky
  • 345
  • 1
  • 5