Skip to content

Commit 5ea8a1b

Browse files
committed
fix: handle NA values in separate_longer_position() (#1625)
- Preserve NA rows in output instead of erroring with 'to' must be a finite number - Handle all-NA and mixed empty/NA edge cases - Add tests for NA handling consistency with separate_longer_delim()
1 parent 06a5edd commit 5ea8a1b

2 files changed

Lines changed: 37 additions & 3 deletions

File tree

R/separate-longer.R

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,31 @@ str_split_length <- function(x, width = 1) {
7777
return(list())
7878
}
7979

80+
na <- is.na(x)
81+
if (all(na)) {
82+
return(rep(list(NA_character_), length(x)))
83+
}
84+
if (any(na)) {
85+
x <- x[!na]
86+
}
87+
8088
max_length <- max(stringr::str_length(x))
81-
idx <- seq(1, max_length, by = width)
8289

83-
pieces <- stringr::str_sub_all(x, cbind(idx, length = width))
84-
pieces <- map(pieces, function(x) x[x != ""])
90+
if (max_length == 0L) {
91+
pieces <- map(x, function(x) character())
92+
} else {
93+
idx <- seq(1, max_length, by = width)
94+
pieces <- stringr::str_sub_all(x, cbind(idx, length = width))
95+
pieces <- map(pieces, function(x) x[x != ""])
96+
}
97+
98+
if (any(na)) {
99+
pieces_na <- vector("list", length(na))
100+
pieces_na[!na] <- pieces
101+
pieces_na[na] <- rep(list(NA_character_), sum(na))
102+
pieces <- pieces_na
103+
}
104+
85105
pieces
86106
}
87107

tests/testthat/test-separate-longer.R

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,20 @@ test_that("works with zero-row data frame", {
3939
expect_equal(separate_longer_delim(df, x, ","), df)
4040
})
4141

42+
test_that("separate_longer_position() handles NA values (#1625)", {
43+
df <- tibble(id = 1:3, x = c("abcd", NA, "ef"))
44+
out <- separate_longer_position(df, x, width = 2)
45+
expect_equal(out$id, c(1, 1, 2, 3))
46+
expect_equal(out$x, c("ab", "cd", NA, "ef"))
47+
})
48+
49+
test_that("separate_longer_position() handles all-NA input", {
50+
df <- tibble(id = 1:2, x = c(NA, NA))
51+
out <- separate_longer_position(df, x, width = 1)
52+
expect_equal(out$id, c(1, 2))
53+
expect_equal(out$x, c(NA_character_, NA_character_))
54+
})
55+
4256
test_that("separate_longer_position() validates its inputs", {
4357
df <- tibble(x = "x")
4458
expect_snapshot(error = TRUE, {

0 commit comments

Comments
 (0)