rguides

dplyr::arrange()

arrange(.data, ..., .by_group = FALSE)

arrange() reorder rows of a data frame based on column values. By default, it sorts in ascending order. Use desc() to sort in descending order. When multiple columns are specified, arrange sorts by the first column, then breaks ties using the second, and so on.

Syntax

arrange(.data, ..., .by_group = FALSE)

Parameters

ParameterTypeDefaultDescription
.datatibble / data.frame,A tibble or data frame to reorder
...column expressions,Columns to sort by, separated by commas. Use desc(col) for descending
.by_grouplogicalFALSEIf TRUE, sort by grouping variables first (from group_by())

Examples

Basic usage

library(dplyr)

df <- data.frame(
  name = c("Charlie", "Alice", "Bob"),
  score = c(85, 92, 78)
)

arrange(df, score)
# # A tibble: 3 × 2
#   name     score
#   <chr>    <dbl>
# 1 Bob         78
# 2 Charlie     85
# 3 Alice       92

Descending order

Sorting ascending is the default, but most analyses benefit from seeing the highest or most recent values first. desc() wraps any column and reverses the sort direction, producing descending order. When multiple columns need mixed directions, wrap only the ones that should be descending while leaving ascending columns unwrapped.

arrange(df, desc(score))
# # A tibble: 3 × 2
#   name     score
#   <chr>    <dbl>
# 1 Alice       92
# 2 Charlie     85
# 3 Bob         78

Multiple columns

When you sort by a single column, rows with equal values appear in their original order — this is not guaranteed to be consistent across runs. Adding a second column as a tiebreaker eliminates this ambiguity. The sorting proceeds left to right through the column list, so the first column determines the primary order, the second resolves ties in the first, and so on.

df2 <- data.frame(
  dept = c("Sales", "Sales", "Engineering", "Engineering"),
  name = c("Bob", "Alice", "Charlie", "David"),
  score = c(78, 85, 92, 88)
)

arrange(df2, dept, desc(score))
# # A tibble: 4 × 3
#   dept       name     score
#   <chr>      <chr>    <dbl>
# 1 Engineering Charlie     92
# 2 Engineering David       88
# 3 Sales       Alice       85
# 4 Sales       Bob         78

Common patterns

These patterns combine arrange() with other dplyr verbs to solve common data ordering tasks. Sorting is often an intermediate step before filtering, mutating, or selecting specific rows, so chaining it with the pipe operator keeps the workflow readable.

Sort with filter

Combine arrange() with filter() to find extremes:

# Get top 3 scores
arrange(df, desc(score)) |> head(3)

Sort by calculated column

Sorting by a raw column is straightforward, but real-world tasks often require sorting by a derived value — the first initial, a computed ratio, or a formatted string. The pattern of mutate() before arrange() lets you create the derived column and sort by it in one pipeline, without polluting your global environment with a temporary variable.

df |> 
  mutate(initials = paste0(substr(name, 1, 1), ".")) |>
  arrange(initials)

Sort with NA values

When a column contains missing values, arrange() pushes them to the end regardless of sort direction. This is intentional — missing data typically represents unknown values that should not be ranked. For datasets with partial completeness, this behavior ensures complete rows appear first and incomplete rows remain visible but at the bottom, rather than being silently excluded.

df <- data.frame(x = c(3, 1, NA, 2))
arrange(df, x)
# # A tibble: 4 × 1
#       x
#   <dbl>
# 1     1
# 2     2
# 3     3
# 4    NA

dplyr::arrange() in practice

arrange() sorts rows by one or more columns. arrange(df, col) sorts ascending. arrange(df, desc(col)) sorts descending. Multiple columns in arrange() are applied in order: arrange(df, group, desc(score)) sorts by group ascending, then by score descending within each group. Base R equivalent: df[order(df$group, -df$score), ].

arrange() uses a stable sort, rows that are equal on all sort keys retain their original relative order. This is important for reproducibility: sorting a data frame by one column then another gives the same result as sorting by both at once.

NA values are sorted to the end by default in arrange(), regardless of ascending or descending. This matches order()’s default na.last = TRUE. To put NA first, use arrange(df, is.na(col), col)is.na(col) is FALSE for non-missing values (which sort first) and TRUE for missing (which sort last in ascending, so they sort first in desc() order).

After group_by(), arrange() sorts within groups by default when .by_group = TRUE. Without .by_group = TRUE, arrange sorts the entire data frame ignoring groups. Use group_by() + arrange(.by_group = TRUE) when you need group-aware ordering, then slice_max() or filter() for within-group top-N selection.

arrange() sorts rows by the specified columns in ascending order. Wrap with desc() for descending: arrange(df, desc(col)). NA values are sorted to the end regardless of direction. When sorting by multiple columns, ties in the first column are broken by the second, and so on. Unlike order() in base R, arrange() returns a data frame — it does not return positions.

See also