#' Reorder a Data Frame #' #' @param df A data frame to be reordered. #' @param x A character scalar specifying the column to be reordered. #' @param y A character scalar specifying the column to order by if ordering by values. #' @param group A character scalar specifying the grouping column (optional). #' @param order A character scalar specifying the order type (one of "none", "y", "grouped"). See details. #' @param dir_order A logical scalar specifying whether to flip the order. #' #' @details Ordering takes the following possible values: #' #' * "none": No reordering. #' * "y": Order by values of y. #' * "grouped_y": Order by values of y and group. #' * "x": Order alphabetically by x. #' * "grouped_x": Order alphabetically by x and group. #' #' #' @return The reordered data frame. #' #' @examples #' # Example usage #' df <- data.frame(col1 = c("b", "a", "c"), col2 = c(10, 25, 3)) #' reorder_by(df, "col1", "col2") #' #' @export reorder_by <- function(df, x, y, group = "", order = "y", dir_order = 1) { #------ Checks # df is a data frame checkmate::assert_data_frame(df) # x and y are character scalar and in df checkmate::assert_character(x, len = 1) checkmate::assert_character(y, len = 1) checkmate::assert_subset(x, colnames(df)) checkmate::assert_subset(y, colnames(df)) # group is character scalar and in df if not empty checkmate::assert_character(group, len = 1) if (group != "") { checkmate::assert_subset(group, colnames(df)) } # order is a character scalar in c("none", "y", "grouped") checkmate::assert_choice(order, c("none", "y", "grouped_y", "x", "grouped_x")) # dir_order is 1 or -1 (numeric scalar) checkmate::assert_subset(dir_order, c(1, -1)) # Convert dir_order to decreasing logical flag dir_order_lgl <- (dir_order == -1) #------ Reorder # droplevels first if (is.factor(df[[x]])) { df[[x]] <- droplevels(df[[x]]) } # reording options if (order == "y") { # Order by values of y df <- df[order(df[[y]], decreasing = dir_order_lgl), ] df[[x]] <- forcats::fct_inorder(df[[x]]) } else if (order == "grouped_y" && group != "") { # Order by group first, then by values of y df <- df[ order( df[[group]], df[[y]], decreasing = c(FALSE, dir_order_lgl), method = "radix" ), ] df[[x]] <- forcats::fct_inorder(df[[x]]) } else if (order == "grouped_y" && group == "") { # Fallback to ordering by y if group is empty rlang::warn("Group is empty. Ordering by y only.") df <- df[order(df[[y]], decreasing = dir_order_lgl), ] df[[x]] <- forcats::fct_inorder(df[[x]]) } else if (order == "x") { # Order alphabetically by x df <- df[order(df[[x]], decreasing = dir_order_lgl), ] df[[x]] <- forcats::fct_inorder(df[[x]]) } else if (order == "grouped_x" && group != "") { # Order by group first, then alphabetically by x df <- df[ order( df[[group]], df[[x]], decreasing = c(FALSE, dir_order_lgl), method = "radix" ), ] df[[x]] <- forcats::fct_inorder(df[[x]]) } else if (order == "grouped_x" && group == "") { # Fallback to ordering by x if group is empty rlang::warn("Group is empty. Ordering by x only.") df <- df[order(df[[x]], decreasing = dir_order_lgl), ] df[[x]] <- forcats::fct_inorder(df[[x]]) } # Reset row names rownames(df) <- NULL return(df) }