Skip to main content
v2026.11,858 entries · CC-BY 4.0
LAC HealthMedical & Research SuppliesReagents, PPE & instruments — chain-of-custody documented.Fast, traceable sourcing built for regulated research environments, from bench consumables to instrumentation.Shop lac.us CodeCASRAIlac.us

Order by in R: order(), arrange() and setorder()

Order by in R with order(), dplyr arrange() and data.table setorder(): multiple columns, descending, NA placement and locale differences.

Written and maintained by CASRAI Editorial Board

Last updated

To order by in R, use order() from base R inside the row index of a data frame: df[order(df$score), ]. order() returns the row positions that would sort the data, so you apply it to the rows yourself. The tidyverse offers arrange() in dplyr, and data.table offers setorder(). They look interchangeable, but they treat missing values and character columns differently, and that difference can change the order of your results.

What ordering is used for in research

Researchers order data frames to rank results (the largest effect sizes first), to inspect extremes and possible data-entry errors, to put time-stamped records in sequence before computing change scores, and to make an exported table read in a stable, documented order. Because the order of rows can affect later steps such as first-observation selection or de-duplication, state how you sorted in your analysis script. For layout of the data itself, see tidy data rules for structuring research data.

Install or access

order() is part of base R, so it needs no installation. Base R is distributed by the R Project through CRAN. The other two tools are add-on packages, installed once and loaded in each session:

install.packages("dplyr")       # provides arrange() and desc()
install.packages("data.table")  # provides setorder()
library(dplyr)
library(data.table)

If you are new to the environment, how to use RStudio covers the editor, and data frames in R covers the object being sorted.

Order by one or more columns

The three approaches below sort the built-in mtcars data by number of cylinders, then by displacement within each cylinder count.

  1. Base R. Pass the sort keys to order() and use the result as the row index (the comma after it matters, because it leaves the columns untouched):
    mtcars[order(mtcars$cyl, mtcars$disp), ]
  2. dplyr. Name the columns directly, with no $:
    arrange(mtcars, cyl, disp)
  3. data.table. setorder() reorders the table by reference, meaning in place, without making a copy:
    dt <- as.data.table(mtcars)
    setorder(dt, cyl, disp)

When the first key has tied values, the second key breaks the tie, then the third, and so on, as documented for order(). If ties remain after all keys, the original row order is kept, because the sort is stable (every method except "quick").

Order in R from largest to smallest (descending)

Each tool has its own switch for descending order:

  • order(x, decreasing = TRUE) reverses a single key. For numbers, order(-x) does the same, but the minus sign works only on numeric keys.
  • arrange(df, desc(x)) uses dplyr’s desc().
  • setorderv(dt, "x", order = -1) sets the direction through the order argument, which takes only 1 (ascending) or -1 (descending).

Ascending on one column, descending on another

The R manual’s own example for mixed directions is dd[order(x, -y, z), ]: ascending on x, descending on y, ascending on z. The same idea in dplyr is arrange(df, x, desc(y), z). A character column cannot take a minus sign. If you need a single decreasing vector with one value per key, the manual states that only method = "radix" accepts a vector, for example order(df$g, df$x, decreasing = c(FALSE, TRUE), method = "radix").

How missing values are sorted

The three tools do not put NA in the same place by default. This is the detail most tutorials leave out, and it matters when a column has gaps. For ways to deal with the gaps themselves, see omitting rows with NA in R.

Tool Default position of NA How to change it
order() (base R) Last (na.last = TRUE) na.last = FALSE puts them first; na.last = NA removes them
arrange() (dplyr) Always at the end for local data, even inside desc() No argument; they stay at the end
setorder() (data.table) First (na.last = FALSE) na.last = TRUE (only TRUE or FALSE are accepted)

The practical consequence: moving the same script from setorder() to arrange() moves the missing rows from the top of the table to the bottom, even though the sort keys are identical.

Why character columns can sort differently

For character vectors, the R manual says that except for method = "radix", the sort order depends on the collating sequence of the locale in use. In other words, base order() on text can give different results on two computers with different language settings. The radix method is not locale-dependent.

dplyr and data.table take a different route. arrange() uses the “C” locale by default (its .locale argument is NULL), and its documentation notes that the C locale is not the same as English locales such as “en”. data.table states that it always reorders in the C locale, which puts uppercase letters before lowercase ones. To get session-locale ordering with data.table, subset with base order(): dt[base::order(name)]. With dplyr, set .locale, for example arrange(df, name, .locale = "en").

For a reproducible analysis, this means a sort on names, site codes or sample IDs that mix upper and lower case is worth pinning down explicitly, rather than relying on whichever tool you used first.

Order by group

On a grouped data frame, arrange() ignores the grouping unless you ask for it. dplyr’s reference shows both behaviours on mtcars grouped by cyl:

by_cyl <- mtcars |> group_by(cyl)
by_cyl |> arrange(desc(wt))                    # ignores groups
by_cyl |> arrange(desc(wt), .by_group = TRUE)  # sorts by group first

With .by_group = TRUE, rows are sorted by the grouping variable first and then by the keys you give. The pipe operator used here is explained in the pipe in R. To sort on several columns that share a name pattern, dplyr’s documentation shows arrange(across(starts_with("Sepal"), desc)) on the iris data.

order() vs sort() vs arrange()

The manual page for order() points to sort, sort.list, rank and xtfrm as related functions. In everyday use the difference is what each returns:

Function What it returns Works on
order(x) The positions that would sort x (an index vector) One or more vectors, so it can drive a data frame sort
sort(x) The sorted values themselves A single vector
arrange(df, x) A data frame with its rows reordered A data frame (dplyr)
setorder(dt, x) The same table, reordered in place A data.table

Output and how to read it

Called on its own, order(x) prints integers, not values. If the first number is 4, then the fourth element of x is the smallest. Using that vector as df[order(df$x), ] then returns the rows in that sequence. Row names (and the row numbers shown at the left) keep their original labels after sorting, so a sorted table can show row names out of numeric sequence; this is expected. Check the first and last few rows with head() and tail(), and see summary statistics in R to confirm the range of the sorted column.

Troubleshooting

  • The data frame did not change. order() and arrange() return a new object. Assign the result, for example df <- df[order(df$x), ]. Only setorder() modifies its input in place.
  • You get columns back instead of rows. The comma is missing. Use df[order(df$x), ], with the comma after the order call.
  • Sorting a whole data frame with do.call(order, df). The manual shows dd[do.call(order, dd), ] to sort on all columns, and warns to remove the column names first (unname), because column names can clash with argument names such as decreasing.
  • Uppercase sorted before lowercase (or the reverse). You are seeing the locale difference described above.
  • Plotting a line out of order. A line chart joins points in row order, so sort on the x variable first. Plotting a line in R uses order() for this.

Free alternatives (table)

All three tools are free and open source. They suit different habits:

Approach Package Direction syntax Modifies in place
df[order(...), ] base R decreasing = TRUE or a minus sign No
arrange() dplyr desc() No
setorder() data.table order = -1 in setorderv() Yes, by reference

FAQ

What does order() do in R?

It returns the positions that would put its arguments into ascending order (descending with decreasing = TRUE). Used as a row index, it sorts a data frame.

How do I order a data frame by a column in R?

Use df[order(df$col), ] in base R, or arrange(df, col) with dplyr.

How do I order by several columns?

List them in priority order: order(df$a, df$b) or arrange(df, a, b). Later columns only break ties in earlier ones.

Where do NA values go?

Last in order() and arrange() by default, first in setorder().

Sources (official docs)

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about Order by in R: order(), arrange() and setorder()

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →