Home > Blockchain >  One-To-One apply/map in R operations
One-To-One apply/map in R operations

Time:09-29

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 (a utility from stats package).

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

CodePudding user response:

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   

CodePudding user response:

mapply also works:

mapply(mutate, tlist, name=names, SIMPLIFY=F)

CodePudding user response:

Using imap

library(purrr)
library(dplyr)
imap(setNames(tlist, names), ~ .x %>%
    mutate(name = .y))
  • Related