Mohit Shah Mohit Shah - 3 years ago 136
R Question

Combine two lists with different structure in R

I have vendor_list

vendor_list[57:59]
[[1]]
[1] "ibm"

[[2]]
[1] "apache" "canonical" "apple" "novell"

[[3]]
[1] "gnu" "oracle"


And I have problemtype_list

problemtype_list[57:59]
[[1]]
[1] "NVD-CWE-Other"

[[2]]
[1] "NVD-CWE-Other"

[[3]]
[1] "CWE-824"


I need to combine them to make a data frame such that such that

A B
ibm NVD-CWE-Other
apache NVD-CWE-Other
canonical NVD-CWE-Other
apple NVD-CWE-Other
novelle NVD-CWE-Other
gnu CWE-824
oracle CWE-824


I have seen similar question Combine two lists in a dataframe in R

But it gives me error

do.call(rbind, Map(data.frame, A=problemtype_list, B=vendor_list))
Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, :
arguments imply differing number of rows: 1, 0


EDIT

My structure of each list

str(vendor_list)
$ : chr "cisco"
$ : NULL
$ : chr [1:5] "redhat" "novell" "debian" "oracle" ...
$ : chr [1:4] "redhat" "novell" "debian" "google"
$ : chr [1:4] "redhat" "novell" "debian" "google"

str(problemtype_list)
$ : chr "CWE-254"
$ : chr "CWE-79"
$ : chr "NVD-CWE-Other"
$ : chr "NVD-CWE-Other"
$ : chr "CWE-254"
$ : chr "CWE-189"
$ : chr "CWE-119"

Answer Source

My guess is that one of your lists has a zero-length element.

vendor_list <- list("ibm", c("apache", "canonical", "apple", "novell"), c("gnu", "oracle"))
problemtype_list <- list("NVD-CWE-Other", "NVD-CWE-Other", "CWE-824")
do.call(rbind.data.frame, Map(data.frame, A=vendor_list, B=problemtype_list))
#           A             B
# 1       ibm NVD-CWE-Other
# 2    apache NVD-CWE-Other
# 3 canonical NVD-CWE-Other
# 4     apple NVD-CWE-Other
# 5    novell NVD-CWE-Other
# 6       gnu       CWE-824
# 7    oracle       CWE-824

However, if we provide an empty slot:

vendor_list[[3]] <- character(0)
vendor_list
# [[1]]
# [1] "ibm"
# [[2]]
# [1] "apache"    "canonical" "apple"     "novell"   
# [[3]]
# character(0)

... and a quick test:

any(lengths(vendor_list) == 0)
# [1] TRUE
any(lengths(problemtype_list) == 0)
# [1] FALSE

... then the merge fails:

do.call(rbind.data.frame, Map(data.frame, A=vendor_list, B=problemtype_list))
# Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE,  (from pit-roads.R!8460QVH#21) : 
#   arguments imply differing number of rows: 0, 1

You can either replace the offending entries with something that makes sense (e.g., NA), or you can remove them. Which method you use depends entirely on your use.

Replacement:

vendor_list[lengths(vendor_list) == 0] <- NA
problemtype_list[lengths(problemtype_list) == 0] <- NA
do.call(rbind.data.frame, Map(data.frame, A=vendor_list, B=problemtype_list))
#           A             B
# 1       ibm NVD-CWE-Other
# 2    apache NVD-CWE-Other
# 3 canonical NVD-CWE-Other
# 4     apple NVD-CWE-Other
# 5    novell NVD-CWE-Other
# 6      <NA>       CWE-824

Removal:

keepthese <- (lengths(vendor_list) > 0) & (lengths(problemtype_list) > 0)
keepthese
# [1]  TRUE  TRUE FALSE
vendor_list <- vendor_list[keepthese]
problemtype_list <- problemtype_list[keepthese]
do.call(rbind.data.frame, Map(data.frame, A=vendor_list, B=problemtype_list))
#           A             B
# 1       ibm NVD-CWE-Other
# 2    apache NVD-CWE-Other
# 3 canonical NVD-CWE-Other
# 4     apple NVD-CWE-Other
# 5    novell NVD-CWE-Other
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download