Skip to content

Commit

Permalink
Add yr_earliest(), yr_latest(), and yr_range(). Closes #43
Browse files Browse the repository at this point in the history
  • Loading branch information
Joe Roe committed Nov 20, 2024
1 parent c41d7bf commit 21244bc
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 8 deletions.
3 changes: 3 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ export(this_year)
export(validate_era)
export(validate_yr)
export(yr)
export(yr_earliest)
export(yr_era)
export(yr_latest)
export(yr_range)
export(yr_set_era)
export(yr_sort)
export(yr_transform)
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# era (development version)

* Added yr_sort() for chronological ordering of year vectors (#44)
* Added `yr_earliest()`, `yr_latest()`, and `yr_range()` for chronological extremes of year vectors (#43)

# era 0.4.1

Expand Down
70 changes: 68 additions & 2 deletions R/yr_sort_range.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@
#' @param ... Other arguments passed to [sort()]; in particular use `na.last` to
#' control NA handling.
#'
#' @details
#' This is implemented as a prefixed function rather than an S3 [sort()] method
#' for [yr]s to avoid surprises when numerical (i.e. not chronological) sorting
#' is expected.
#'
#' @return Sorted [yr] vector
#'
#' @family functions for chronological ordering and ranges
#' @family functions for chronological ordering and extremes
#'
#' @export
#'
Expand All @@ -23,11 +28,72 @@
#' x <- yr(c(200, 100, 300), "CE")
#' yr_sort(x)
#' yr_sort(x, reverse = TRUE)

#'
#' # Backward-counting era:
#' y <- yr(c(200, 100, 300), "BCE")
#' yr_sort(y)
#' yr_sort(y, reverse = TRUE)
yr_sort <- function(x, reverse = FALSE, ...) {
sort(x, decreasing = xor(era_direction(yr_era(x)) < 0, reverse), ...)
}

#' Chronological minima and maxima
#'
#' Returns the chronologically earliest and/or latest value in a vector of
#' years, i.e. era-aware version [min()], [max()], and [range()].
#'
#' @param x A [yr] vector with era
#' @param na.rm a logical indicating whether missing values should be removed
#'
#' @details
#' These are implemented as prefixed functions rather than S3 [min()], [max()],
#' and [range()] methods for [yr]s to avoid surprises when numerical (i.e. not
#' chronological) extremes are expected.
#'
#' @return
#' For `yr_earliest()` and `yr_leatest()`, a `yr` vector of length 1 with the
#' earliest or latest value.
#'
#' For `yr_range()`, a `yr` vector of length 2 with the earliest and latest
#' value (in that order).
#'
#' If `x` contains `NA` values and `na.rm = FALSE` (the default), only `NA`s
#' will be returned.
#'
#' @family functions for chronological ordering and extremes
#'
#' @examples
#' # Forward-counting era:
#' x <- yr(c(200, 100, 300), "CE")
#' yr_earliest(x)
#' yr_latest(x)
#' yr_range(x)
#'
#' # Backward-counting era:
#' y <- yr(c(200, 100, 300), "BCE")
#' yr_earliest(y)
#' yr_latest(y)
#' yr_range(x)
#'
#' @name yr_extremes
NULL

#' @rdname yr_extremes
#' @export
yr_earliest <- function(x, na.rm = FALSE) {
if (era_direction(yr_era(x)) < 0) max(x, na.rm = na.rm)
else min(x, na.rm = na.rm)
}

#' @rdname yr_extremes
#' @export
yr_latest <- function(x, na.rm = FALSE) {
if (era_direction(yr_era(x)) < 0) min(x, na.rm = na.rm)
else max(x, na.rm = na.rm)
}

#' @rdname yr_extremes
#' @export
yr_range <- function(x, na.rm = FALSE) {
yr_sort(range(x, na.rm = na.rm))
}
58 changes: 58 additions & 0 deletions man/yr_extremes.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion man/yr_sort.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 24 additions & 5 deletions tests/testthat/test-yr_sort_range.R
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
test_that("yr_sort() correctly handles era direction", {
forward_yr <- yr(c(200, 100, 300), "CE")
backward_yr <- yr(c(200, 100, 300), "BCE")
forward_yr <- yr(c(200, 100, 300), "CE")
backward_yr <- yr(c(200, 100, 300), "BCE")

test_that("yr_sort() respects era direction", {
forward_sort <- yr_sort(forward_yr)
backward_sort <- yr_sort(backward_yr)
forward_rev_sort <- yr_sort(forward_yr, reverse = TRUE)
backward_rev_sort <- yr_sort(backward_yr, reverse = TRUE)

expect_lt(forward_sort[1], forward_sort[3])
expect_gt(backward_sort[1], backward_sort[3])
})

test_that("yr_sort(reverse = TRUE) respects era direction", {
forward_rev_sort <- yr_sort(forward_yr, reverse = TRUE)
backward_rev_sort <- yr_sort(backward_yr, reverse = TRUE)

expect_gt(forward_rev_sort[1], forward_rev_sort[3])
expect_lt(backward_rev_sort[1], backward_rev_sort[3])
})

test_that("yr_earliest() respects era direction", {
expect_equal(yr_earliest(forward_yr), min(forward_yr))
expect_equal(yr_earliest(backward_yr), max(backward_yr))
})

test_that("yr_latest() respects era direction", {
expect_equal(yr_latest(forward_yr), max(forward_yr))
expect_equal(yr_latest(backward_yr), min(backward_yr))
})

test_that("yr_range() respects era direction", {
expect_equal(yr_range(forward_yr), range(forward_yr))
expect_equal(yr_range(backward_yr), rev(range(backward_yr)))
})

0 comments on commit 21244bc

Please sign in to comment.