dlaser
dlaser

Reputation: 1345

Apply function to corresponding elements in list of data frames

I have a list of data frames in R. All of the data frames in the list are of the same size. However, the elements may be of different types. For example,

enter image description here

I would like to apply a function to corresponding elements of data frame. For example, I want to use the paste function to produce a data frame such as

"1a" "2b" "3c"

"4d" "5e" "6f"

Is there a straightforward way to do this in R. I know it is possible to use the Reduce function to apply a function on corresponding elements of dataframes within lists. But using the Reduce function in this case does not seem to have the desired effect.

Reduce(paste,l)

Produces:

"c(1, 4) c(\"a\", \"d\")" "c(2, 5) c(\"b\", \"e\")" "c(3, 6) c(\"c\", \"f\")"

Wondering if I can do this without writing messy for loops. Any help is appreciated!

Upvotes: 4

Views: 340

Answers (2)

thelatemail
thelatemail

Reputation: 93813

To explain @mnel's excellent answer a bit more, consider the simple example of summing the corresponding elements of two vectors:

Map(sum,1:3,4:6)

[[1]]
[1] 5  # sum(1,4)

[[2]]
[1] 7  # sum(2,5)

[[3]]
[1] 9  # sum(3,6)

Map(sum,list(1:3,4:6))

[[1]]
[1] 6  # sum(1:3)

[[2]]
[1] 15 # sum(4:6)

Why the second one is the case might be made more obvious by adding a second list, like:

Map(sum,list(1:3,4:6),list(0,0))

[[1]]
[1] 6  # sum(1:3,0)

[[2]]
[1] 15 # sum(4:6,0)

Now, the next is more tricky. As the help page ?do.call states:

 ‘do.call’ constructs and executes a function call from a name or a
 function and a list of arguments to be passed to it.

So, doing:

do.call(Map,c(sum,list(1:3,4:6)))

calls Map with the inputs of the list c(sum,list(1:3,4:6)), which looks like:

[[1]] # first argument to Map
function (..., na.rm = FALSE)  .Primitive("sum") # the 'sum' function

[[2]] # second argument to Map
[1] 1 2 3

[[3]] # third argument to Map
[1] 4 5 6

...and which is therefore equivalent to:

Map(sum, 1:3, 4:6)

Looks familiar! It is equivalent to the first example at the top of this answer.

Upvotes: 4

mnel
mnel

Reputation: 115382

Instead of Reduce, use Map.

 # not quite the same as your data
 l <- list(data.frame(matrix(1:6,ncol=3)),
           data.frame(matrix(letters[1:6],ncol=3), stringsAsFactors=FALSE))
 # this returns a list
 LL <- do.call(Map, c(list(f=paste0),l))
 #
 as.data.frame(LL)
 #  X1 X2 X3
 # 1 1a 3c 5e
 # 2 2b 4d 6f

Upvotes: 7

Related Questions