diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 0d515a3a..10d3dd98 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -18,7 +18,7 @@ If you’ve found a bug, please file an issue that illustrates the bug with a mi ### Pull request process -* Fork the package and clone onto your computer. If you haven't done this before, we recommend using `usethis::create_from_github("batpigandme/forcats", fork = TRUE)`. +* Fork the package and clone onto your computer. If you haven't done this before, we recommend using `usethis::create_from_github("tidyverse/forcats", fork = TRUE)`. * Install all development dependences with `devtools::install_dev_deps()`, and then make sure the package passes R CMD check by running `devtools::check()`. If R CMD check doesn't pass cleanly, it's a good idea to ask for help before continuing. diff --git a/DESCRIPTION b/DESCRIPTION index ce124d87..d81111d9 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -38,4 +38,4 @@ Config/testthat/edition: 3 Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1 diff --git a/NAMESPACE b/NAMESPACE index c99421cf..3a88140a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -43,6 +43,7 @@ export(lvls_expand) export(lvls_reorder) export(lvls_revalue) export(lvls_union) +export(ord) import(rlang) importFrom(glue,glue) importFrom(lifecycle,deprecated) diff --git a/NEWS.md b/NEWS.md index b138b7a4..ddcbf712 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,9 +6,13 @@ * New `fct_na_value_to_level()` and `fct_na_level_to_value()` to convert NA values to NA levels and vice versa (#337). + +* New `ord()` is a shortcut for `fct(..., ordered = TRUE)` ## Minor improvement and bug fixes +* `fct()` now accepts an `ordered` argument (#363) + * All functions now validate their inputs, giving more useful errors if you accidentally misspecify an input. diff --git a/R/fct.R b/R/fct.R index db8f6804..2788471c 100644 --- a/R/fct.R +++ b/R/fct.R @@ -1,13 +1,16 @@ #' Create a factor #' -#' `fct()` is a stricter version of [factor()] that errors if your -#' specification of `levels` is inconsistent with the values in `x`. +#' `fct()` and `ord()` are stricter versions of [factor()] and [ordered()] that +#' error if your specification of `levels` is inconsistent with the values in +#' `x`. #' #' @param x A character vector. Values must occur in either `levels` or `na`. #' @param levels A character vector of known levels. If not supplied, will #' be computed from the unique values of `x`, in the order in which they #' occur. #' @param na A character vector of values that should become missing values. +#' @param ordered logical flag to determine if the levels should be regarded as +#' ordered. #' @return A factor. #' @export #' @examples @@ -19,6 +22,10 @@ #' # in the order that they're seen #' fct(x) #' +#' # To create ordered factors, use ord() +#' x <- c("B", "A", "C", "D", "A", "F") +#' ord(x, levels = c("F", "D", "C", "B", "A")) +#' #' #' # Differences with base R ----------------------------------------------- #' # factor() silently generates NAs @@ -33,7 +40,8 @@ #' factor(c("y", "x")) #' # fct() uses in order of appearance: #' fct(c("y", "x")) -fct <- function(x = character(), levels = NULL, na = character()) { +fct <- function(x = character(), levels = NULL, na = character(), + ordered = FALSE) { check_character(x) check_character(levels, allow_null = TRUE) check_character(na) @@ -53,5 +61,12 @@ fct <- function(x = character(), levels = NULL, na = character()) { )) } - factor(x, levels = levels, exclude = NULL) + factor(x, levels = levels, exclude = NULL, ordered = ordered) +} + + +#' @export +#' @rdname fct +ord <- function(x = character(), levels = NULL, na = character()) { + fct(x, levels, na, ordered = TRUE) } diff --git a/man/fct.Rd b/man/fct.Rd index de0dcb6d..d653434c 100644 --- a/man/fct.Rd +++ b/man/fct.Rd @@ -2,9 +2,12 @@ % Please edit documentation in R/fct.R \name{fct} \alias{fct} +\alias{ord} \title{Create a factor} \usage{ -fct(x = character(), levels = NULL, na = character()) +fct(x = character(), levels = NULL, na = character(), ordered = FALSE) + +ord(x = character(), levels = NULL, na = character()) } \arguments{ \item{x}{A character vector. Values must occur in either \code{levels} or \code{na}.} @@ -14,13 +17,17 @@ be computed from the unique values of \code{x}, in the order in which they occur.} \item{na}{A character vector of values that should become missing values.} + +\item{ordered}{logical flag to determine if the levels should be regarded as +ordered.} } \value{ A factor. } \description{ -\code{fct()} is a stricter version of \code{\link[=factor]{factor()}} that errors if your -specification of \code{levels} is inconsistent with the values in \code{x}. +\code{fct()} and \code{ord()} are stricter versions of \code{\link[=factor]{factor()}} and \code{\link[=ordered]{ordered()}} that +error if your specification of \code{levels} is inconsistent with the values in +\code{x}. } \examples{ # Use factors when you know the set of possible values a variable might take @@ -31,6 +38,10 @@ fct(x, levels = c("O", "A", "B", "AB")) # in the order that they're seen fct(x) +# To create ordered factors, use ord() +x <- c("B", "A", "C", "D", "A", "F") +ord(x, levels = c("F", "D", "C", "B", "A")) + # Differences with base R ----------------------------------------------- # factor() silently generates NAs diff --git a/tests/testthat/test-fct.R b/tests/testthat/test-fct.R index a19cb16b..5cfcb12b 100644 --- a/tests/testthat/test-fct.R +++ b/tests/testthat/test-fct.R @@ -22,7 +22,7 @@ test_that("checks input types", { test_that("clear error if levels are incomplete", { expect_snapshot(error = TRUE, - fct(c("x", "y", "z"), c("x", "y")) + fct(c("x", "y", "z"), c("x", "y")) ) }) @@ -40,3 +40,13 @@ test_that("can covert values to implicit or explcit NA", { factor(c("x", "y", NA), levels = c("x", "y", NA), exclude = NULL) ) }) + +test_that("can return ordered factors", { + expect_s3_class(fct(c("x", "y"), ordered = TRUE), "ordered") + expect_s3_class(ord(c("x", "y")), "ordered") + + expect_equal( + ord(c("y", "x", "z"), levels = c("x", "y", "z")), + ordered(c("y", "x", "z"), levels = c("x", "y", "z")) + ) +})