Reputation: 3294
In this example, I have two lists
tiers <- list("tier 1", "tier 2", "tier 3")
main <- list(data.frame(a = c("this", "that")),
data.frame(a = c("the other", "that too")),
data.frame(a = c("once more", "kilgore trout")))
and I'd like to mutate()
each list element (i.e., data.frame()
) in main
by adding the value in tiers
from the corresponding element. I thought mapply()
would do it:
library(dplyr)
mapply(function(x, y) y %>% mutate(tier = x), tiers, main)
but I get an unexpected result
> mapply(function(x, y) y %>% mutate(tier = x), tiers, main)
[,1] [,2] [,3]
a factor,2 factor,2 factor,2
tier Character,2 Character,2 Character
while what I expected was
[[1]]
a tier
1 this tier 1
2 that tier 1
[[2]]
a tier
1 the other tier 2
2 that too tier 2
[[3]]
a tier
1 once more tier 3
2 kilgore trout tier 3
Am I using mapply()
correctly? If not, is there something I should be using to get the result I'm expecting? I should note that actual data may have up to n
list elements; I can't hard-code any values in terms of 1:n
.
Upvotes: 4
Views: 446
Reputation: 47340
In base R
you could use Map
with the function data.frame
if you name the tier
argument :
Map(data.frame, main, tier=tiers)
# [[1]]
# a tier
# 1 this tier 1
# 2 that tier 1
#
# [[2]]
# a tier
# 1 the other tier 2
# 2 that too tier 2
#
# [[3]]
# a tier
# 1 once more tier 3
# 2 kilgore trout tier 3
Upvotes: 2
Reputation: 887691
We can do this in tidyverse
with map2
library(tidyverse)
map2(main, tiers, ~ .x %>%
mutate(tiers = .y))
#[[1]]
# a tiers
#1 this tier 1
#2 that tier 1
#[[2]]
# a tiers
#1 the other tier 2
#2 that too tier 2
#[[3]]
# a tiers
#1 once more tier 3
#2 kilgore trout tier 3
Upvotes: 1
Reputation: 107707
Also, consider within
or transform
with Map
(list version wrapper to mapply
) and avoid loading a package for one function, mutate
:
Map(function(x, y) within(y, tier <- x), tiers, main)
Map(function(x, y) transform(y, tier = x), tiers, main)
Upvotes: 2
Reputation: 389175
What you needed was to add SIMPLIFY = FALSE
in your mapply
call
library(dplyr)
mapply(function(x, y) y %>% mutate(tier = x), tiers, main, SIMPLIFY = FALSE)
# a tier
#1 this tier 1
#2 that tier 1
#[[2]]
# a tier
#1 the other tier 2
#2 that too tier 2
#[[3]]
# a tier
#1 once more tier 3
#2 kilgore trout tier 3
?mapply
says
SIMPLIFY - attempt to reduce the result to a vector, matrix or higher dimensional array;
SIMPLIFY
argument is by default TRUE
in mapply
and FALSE
in Map
Map(function(x, y) y %>% mutate(tier = x), tiers, main)
If you want to keep everything in base R, you could use cbind
Map(cbind, main, tiers)
Upvotes: 2