简体   繁体   中英

R: Merge each dataframe in a list with a different column in a dataframe

I am trying to merge each dataframe in a list of dataframes with a different column of a single dataframe. That is, the dataframe in list element 1 should be merged with row 1 of the single dataframe, the dataframe in list element 2 should be merged with row 2 of the single dataframe and so on. It's easier to understand with an example.

Here is my list of dataframes:

df1 <- data.frame(col1 = 11:14, col2 = 11:14)
df2 <- data.frame(col1 = 12:15, col2 = 12:15)
df3 <- data.frame(col1 = 13:16, col2 = 13:16)

df_list <- list(df1, df2, df3)

So df_list looks like this:

[[1]]
  col1 col2
1   11   11
2   12   12
3   13   13
4   14   14

[[2]]
  col1 col2
1   12   12
2   13   13
3   14   14
4   15   15

[[3]]
  col1 col2
1   13   13
2   14   14
3   15   15
4   16   16

Here is my single dataframe:

df_to_merge <- data.frame(col3 = 1:3, col4 = 4:6)
  col3 col4
1    1    4
2    2    5
3    3    6

I can easily achieve the result I want with a loop:

what_i_want <- list()
for (i in 1:nrow(df_to_merge)) {
  what_i_want[[i]] <- merge.data.frame(df_list[[i]], df_to_merge[i, ])
}

Which gives:

[[1]]
  col1 col2 col3 col4
1   11   11    1    4
2   12   12    1    4
3   13   13    1    4
4   14   14    1    4

[[2]]
  col1 col2 col3 col4
1   12   12    2    5
2   13   13    2    5
3   14   14    2    5
4   15   15    2    5

[[3]]
  col1 col2 col3 col4
1   13   13    3    6
2   14   14    3    6
3   15   15    3    6
4   16   16    3    6

Is there a more elegant way to do this with a combination of eg lapply() and apply() ? Or mapply() ? I tried, but the only thing I could manage was to combine each element of the list with each row of the single dataframe, which I don't want.

Thanks in advance for any creative solutions!

You're basically there now:

what_i_want <- lapply(seq_along(df_list), function(i) { merge.data.frame(df_list[[i]], df_to_merge[i,]) })

Result:

> what_i_want
[[1]]
  col1 col2 col3 col4
1   11   11    1    4
2   12   12    1    4
3   13   13    1    4
4   14   14    1    4

[[2]]
  col1 col2 col3 col4
1   12   12    2    5
2   13   13    2    5
3   14   14    2    5
4   15   15    2    5

[[3]]
  col1 col2 col3 col4
1   13   13    3    6
2   14   14    3    6
3   15   15    3    6
4   16   16    3    6

You can split df_to_merge at each row and use Map to cbind

Map(cbind, df_list, split(df_to_merge, seq_len(nrow(df_to_merge))))

#[1]]
#  col1 col2 col3 col4
#1   11   11    1    4
#2   12   12    1    4
#3   13   13    1    4
#4   14   14    1    4

#[[2]]
#  col1 col2 col3 col4
#1   12   12    2    5
#2   13   13    2    5
#3   14   14    2    5
#4   15   15    2    5

#[[3]]
#  col1 col2 col3 col4
#1   13   13    3    6
#2   14   14    3    6
#3   15   15    3    6
#4   16   16    3    6

A tidyverse way of the same logic could be

library(dplyr)
library(purrr)

map2(df_list, df_to_merge %>% group_split(row_number(), keep = FALSE), cbind)

Here is a base R solution using lapply() and cbind()

dfout <- lapply(seq(df_list), function(k) cbind(df_list[[k]],df_to_merge[k,],row.names = NULL))

such that

> dfout
[[1]]
  col1 col2 col3 col4
1   11   11    1    4
2   12   12    1    4
3   13   13    1    4
4   14   14    1    4

[[2]]
  col1 col2 col3 col4
1   12   12    2    5
2   13   13    2    5
3   14   14    2    5
4   15   15    2    5

[[3]]
  col1 col2 col3 col4
1   13   13    3    6
2   14   14    3    6
3   15   15    3    6
4   16   16    3    6

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM