Search code examples
rmapreducelapplysapply

One-To-One apply/map in R operations


I've got 3 tibbles in a list that I would like to add a column, for each, with a different value. I found it struggling to do this apart from using the usual for loop (granted, for may well be the best solution in this use case, but I am curious if there's a clever solution).

library(tibble)
library(dplyr)

t1 <- tibble(a=1:10, b=2:11, c=3:12)
t2 <- tibble(a=1:10, b=2:11, c=3:12)
t3 <- tibble(a=1:10, b=2:11, c=3:12)
tlist <- list(t1, t2, t3)

names <- c("A", "B", "C")

The result I wanted to achieve would be the same as that we do dplyr::mutate on each tibble to add that extra column with values in names respectively; to illustrate:

t1 %>% mutate(name=names[1])
t2 %>% mutate(name=names[2])
t3 %>% mutate(name=names[3])

I've tried lapply, sapply, and mapply (and some combinations of either two of them), or purrr::map, I couldn't see a way of applying mutate action of a single value on a single tibble (i.e., one-to-one apply/map). Python has zip which sometimes creates a pair of values that we can easily access in apply functions, but we don't have that facility in R.

A piece of pusedo-ish code in R (which mimics what zip in Python would be like):

args <- pair(tlist, names)

add.col <- function(arg.pair) -> {
    arg.pair[[1]] %>% mutate(name=arg.pair[[2]])
}

res <- args %>% lapply(add.col)

Note that apply functions do not take in Pair object (an utility from stats package).

It's very likely there's blind spot for me as I became increasingly obsessed with apply; is there a clever way to do this one-to-one mapping?


Solution

  • Use map2:

    library(purrr)
    library(dplyr)
    map2(tlist, names, 
         ~ .x %>% 
           mutate(name = .y))
    

    Or in base R with Map:

    Map(function(x, y) transform(x, name = y), tlist, names)
    

    output:

    [[1]]
    # A tibble: 10 × 4
           a     b     c name 
       <int> <int> <int> <chr>
     1     1     2     3 A    
     2     2     3     4 A    
     3     3     4     5 A    
     4     4     5     6 A    
     5     5     6     7 A    
     6     6     7     8 A    
     7     7     8     9 A    
     8     8     9    10 A    
     9     9    10    11 A    
    10    10    11    12 A    
    
    [[2]]
    # A tibble: 10 × 4
           a     b     c name 
       <int> <int> <int> <chr>
     1     1     2     3 B    
     2     2     3     4 B    
     3     3     4     5 B    
     4     4     5     6 B    
     5     5     6     7 B    
     6     6     7     8 B    
     7     7     8     9 B    
     8     8     9    10 B    
     9     9    10    11 B    
    10    10    11    12 B    
    
    [[3]]
    # A tibble: 10 × 4
           a     b     c name 
       <int> <int> <int> <chr>
     1     1     2     3 C    
     2     2     3     4 C    
     3     3     4     5 C    
     4     4     5     6 C    
     5     5     6     7 C    
     6     6     7     8 C    
     7     7     8     9 C    
     8     8     9    10 C    
     9     9    10    11 C    
    10    10    11    12 C