25

I have two lists with different structure:

listA <- list(c("a","b","c"), c("d","e"))
listB <- list(0.05, 0.5)

listA
[[1]]
[1] "a" "b" "c"

[[2]]
[1] "d" "e"

listB
[[1]]
[1] 0.05

[[2]]
[1] 0.5

I have an idea of how to use looping to combine both lists in a dataframe that looks like the one below but I'm sure that there is a more efficient way of doing this.

data.frame(A = c("a","b","c","d","e"), B = c(rep(0.05,3), rep(0.5,2)))
  A    B
1 a 0.05
2 b 0.05
3 c 0.05
4 d 0.50
5 e 0.50
shadow
  • 21,823
  • 4
  • 63
  • 77
Rami Al-Fahham
  • 617
  • 1
  • 6
  • 10

7 Answers7

37

This is another option:

do.call(rbind, Map(data.frame, A=listA, B=listB))

#   A    B
# 1 a 0.05
# 2 b 0.05
# 3 c 0.05
# 4 d 0.50
# 5 e 0.50
Matthew Plourde
  • 43,932
  • 7
  • 96
  • 113
5

Maybe there is a more elegant way that keeps the class numeric of list2's elements... But this one works as well

df <- do.call(rbind,mapply(cbind, listA, listB))
df <- as.data.frame(df, stringsAsFactors = FALSE)
df[,2] <- as.numeric(df[,2])

EDIT Way better is Matthew Plourde's solution using Map aka mapply(data.frame, A=listA, B=listB, SIMPLIFY = FALSE)

Rentrop
  • 20,979
  • 10
  • 72
  • 100
4

If looking for a tidyverse solution, here is the analogue to the accepted answer. Using the dfr suffix to the map function family enables a very simple solution which should also be faster than do.call("rbind").

library(tidyverse)
listA <- list(c("a","b","c"), c("d","e"))
listB <- list(0.05, 0.5)

map2_dfr(listA, listB, ~ tibble(A = .x, B = .y))
#> # A tibble: 5 x 2
#>   A         B
#>   <chr> <dbl>
#> 1 a      0.05
#> 2 b      0.05
#> 3 c      0.05
#> 4 d      0.5 
#> 5 e      0.5

Created on 2019-02-12 by the reprex package (v0.2.1)

Calum You
  • 14,687
  • 4
  • 23
  • 42
  • best solution because there are no ugly row names! – Peter Apr 04 '20 at 19:35
  • @ Calum You can you explain the meaning of .x and .y? Which letters beside .x and .y should I use if I have lists A,B,C and D instead of only A and B? Thank you! – user2165379 Mar 19 '23 at 13:03
  • @user2165379 see the documentation for map2; .x and .y are placeholders for the first and second arguments to the function. you'll want pmap for arbitrary argument number functions and ..1, ..2 placeholders. – Calum You Mar 20 '23 at 07:30
  • @ Calum You thank you. I will look into pmap. – user2165379 Mar 20 '23 at 12:44
3

Another way without using do.call:

cbind(data.frame(listA), data.frame(listB))
S.Zhong
  • 66
  • 3
2

I'd prefer this:

do.call(rbind,
        Map(function(...) setNames(cbind.data.frame(...), 
                                   c("A", "B")), 
            listA, listB))
#  A    B
#1 a 0.05
#2 b 0.05
#3 c 0.05
#4 d 0.50
#5 e 0.50
Roland
  • 127,288
  • 10
  • 191
  • 288
1

Here is another way:

do.call(rbind,
        lapply(1:length(listA),
               function(i)
                 data.frame(A=unlist(listA[i]),
                            B=unlist(listB[i]))))
zx8754
  • 52,746
  • 12
  • 114
  • 209
0

This places the index and renames the columns appropriately:

df <- do.call(rbind.data.frame, Map('c', listA, listB))
colnames(df)[1] <- "A"
colnames(df)[2] <- "B"
Carlo Carandang
  • 187
  • 1
  • 8