Convert Vectors to Range String
to_range.Rd
Converts vectors to a string of ranges. All vector types are accepted and the
original values will appear in the final output range, but where input is not
a numeric vector of whole numbers, a function to convert
the values to integers must be provided (int_fn
) for the purpose of
identifying the range(s).
Usage
to_range(
x,
int_fn = NULL,
...,
sep = c(",", "-"),
start_rm = NULL,
end_rm = NULL
)
Arguments
- x
A numeric vector of whole numbers.
- int_fn
A function (or tidyverse-style formula) to convert
x
into an integer vector, used ONLY for creating ranges; the original value will appear in the range except where modified bystart_rm
and/orend_rm
.int_fun
is required whenx
is not a numeric vector.- ...
Arguments passed on to
int_fn
.- sep
The separators to use between ranges (default: ',') and within a range (default: '-'), as a length-2 character vector.
- start_rm
A regular expression to remove from
x
values at the beginning of a range.- end_rm
A regular expression to remove from
x
values at the end of a range.
Notes
NA
values are always dropped.to_range()
was inspired by answers at https://stackoverflow.com/q/16911773/6938922, most heavily by speendo (CC-BY-SA 3.0, accessed 2022-07-01). This is the fastest approach with few inputs but is significantly slower than other answers for large inputs. The internal approach will likely be modified in the future, but arguments and output will remain the same.
Examples
x <- c(1:2, 8:6, 4, -1:-2, 20:37, 4, 40, 43, 45)
to_range(x)
#> [1] "-2,-1,1,2,4,6-8,20-37,40,43,45"
# `NA` values are dropped
y <- c(1:4, NA, 5, 7:10)
to_range(x)
#> [1] "-2,-1,1,2,4,6-8,20-37,40,43,45"
# Use `int_fn` when `x` is not a numeric vector (tidyverse-style formulas
# accepted)
x_char <- as.character(x)
to_range(x, int_fn = as.integer)
#> [1] "-2,-1,1,2,4,6-8,20-37,40,43,45"
to_range(x, int_fn = ~ as.integer(.x))
#> [1] "-2,-1,1,2,4,6-8,20-37,40,43,45"
# `int_fn` allows non-numeric ranges to be created
txt <- paste0(x, "txt")
to_int <- function(x, y) as.integer(stringr::str_remove(x, "txt"))
to_range(txt, to_int, y = "txt")
#> [1] "-2txt,-1txt,1txt,2txt,4txt,6txt-8txt,20txt-37txt,40txt,43txt,45txt"
# text can be selectively removed from the values at the beginning of ranges
# (`start_rm`) or end of ranges (`end_rm`)
to_range(txt, to_int, start_rm = "txt")
#> [1] "-2txt,-1txt,1txt,2txt,4txt,6-8txt,20-37txt,40txt,43txt,45txt"
to_range(txt, to_int, end_rm = "txt")
#> [1] "-2txt,-1txt,1txt,2txt,4txt,6txt-8,20txt-37,40txt,43txt,45txt"