From 1526aca21ca7968d9dbc43a657ac0a30230e7d7c Mon Sep 17 00:00:00 2001 From: Lionel Henry Date: Mon, 19 Apr 2021 17:57:24 +0200 Subject: [PATCH] Fix data frame initialisation in `bind_rows()` (#5502) Closes #5417 Closes #5749 Add unit tests for `bind_rows()` Contributed by @StevenMMortimer in #5429 --- NEWS.md | 5 +++ R/bind.r | 2 +- tests/testthat/test-bind.R | 71 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index fd7fc0e4de..1b0ec2501d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,11 @@ # dplyr (development version) +* Fixed issue in `bind_rows()` causing lists to be incorrectly transformed as + data frames (#5417, #5749). + * `select()` no longer creates duplicate variables when renaming a variable to the same name as a grouping variable (#5841). + * Fixed behaviour of `...` in top-level `across()` calls (#5813, #5832). * `dplyr_col_select()` keeps attributes for bare data frames (#5294, #5831). @@ -85,6 +89,7 @@ * dplyr now depends on R 3.3.0 + # dplyr 1.0.2 * Fixed `across()` issue where data frame columns would mask objects referred to diff --git a/R/bind.r b/R/bind.r index 68dde0ba93..03d8e48e79 100644 --- a/R/bind.r +++ b/R/bind.r @@ -128,7 +128,7 @@ bind_rows <- function(..., .id = NULL) { first <- dots[[1L]] dots <- map(dots, function(.x) { if (vec_is_list(.x)) { - .x <- new_data_frame(as.list(.x)) + .x <- vctrs::data_frame(!!!.x) } .x }) diff --git a/tests/testthat/test-bind.R b/tests/testthat/test-bind.R index 0dd3f4fbc8..5461b2d8ab 100644 --- a/tests/testthat/test-bind.R +++ b/tests/testthat/test-bind.R @@ -550,6 +550,77 @@ test_that("bind_rows() correctly restores (#2457)", { expect_s3_class(df$x, "vctrs_list_of") }) +test_that("bind_rows() validates lists (#5417)", { + out <- bind_rows(list(x = 1), list(x = 1, y = 1:2)) + expect_identical(out, tibble(x = c(1, 1, 1), y = c(NA, 1:2))) + + x <- vctrs::list_of(a = data.frame(x = 1), b = data.frame(y = 2:3)) + out <- bind_rows(x) + exp <- tibble( + a = vctrs::data_frame(x = c(1, 1), y = int(NA, NA)), + b = vctrs::data_frame(x = dbl(NA, NA), y = 2:3) + ) + expect_identical(out, exp) +}) + +test_that("bind_rows() handles missing, null, and empty elements (#5429)", { + x <- list(a = "A", b = 1) + y <- list(a = "B", b = 2) + l <- list(x, y) + expect_identical( + bind_rows(l), + tibble(a = c("A", "B"), b = c(1, 2)) + ) + + x <- list(a = NA, b = NA) + y <- list(a = "B", b = 2) + l <- list(x, y) + expect_identical( + bind_rows(l), + tibble(a = c(NA, "B"), b = c(NA, 2)) + ) + + x <- list(a = NULL, b = NULL) + y <- list(a = "B", b = 2) + l <- list(x, y) + expect_identical( + bind_rows(l), + tibble(a = "B", b = 2) + ) + + x <- list(a = NULL, b = 1) + y <- list(a = "B", b = 2) + l <- list(x, y) + expect_identical( + bind_rows(l), + tibble(b = c(1, 2), a = c(NA, "B")) + ) + + x <- list(a = character(0), b = 1) + y <- list(a = "B", b = 2) + l <- list(x, y) + expect_identical( + bind_rows(l), + tibble(a = "B", b = 2) + ) + + x <- list(a = character(0), b = 1:2) + y <- list(a = "B", b = 2) + l <- list(x, y) + expect_error( + bind_rows(l), + class = "vctrs_error_incompatible_size" + ) + + x <- list(a = letters[1:3], b = 1:2) + y <- list(a = "B", b = 2) + l <- list(x, y) + expect_error( + bind_rows(l), + class = "vctrs_error_incompatible_size" + ) +}) + # Errors ------------------------------------------------------------------