Sorting Data Frames by Column
Sort entire data frames using order() and dplyr's arrange().
Sorting Data Frames by Column is a free R Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the R Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Sorting a Data Frame by One Column
The standard base-R way to sort a data frame is to use order() on the column of interest and use the resulting indices to reorder the rows. The comma after the indices selects all columns.
df <- data.frame(
name = c('Charlie', 'Alice', 'Bob', 'Diana'),
age = c(35, 28, 42, 31),
salary = c(55000, 48000, 72000, 61000)
)
df[order(df$age), ]Sorting Descending with Negation
For numeric columns, negate the column inside order() to reverse the sort direction. The minus sign flips all values so that what was the maximum becomes the minimum for ordering purposes.
df <- data.frame(
name = c('Charlie', 'Alice', 'Bob', 'Diana'),
salary = c(55000, 48000, 72000, 61000)
)
# Highest salary first
df[order(-df$salary), ]Multi-Column Sort
Pass multiple columns to order() to sort by primary, then secondary criteria. The second argument breaks ties in the first. This mirrors SQL's ORDER BY col1, col2.
df <- data.frame(
dept = c('Eng', 'HR', 'Eng', 'HR', 'Eng'),
name = c('Zara', 'Bob', 'Alice', 'Eve', 'Mike'),
salary = c(90000, 55000, 85000, 58000, 78000)
)
# Sort by dept, then by salary descending within dept
df[order(df$dept, -df$salary), ]Sorting Character Columns
Sorting by a character column works the same way — order() handles lexicographic ordering. For reverse alphabetical order, use decreasing = TRUE instead of negation (negation only works for numerics).
df <- data.frame(
city = c('Paris', 'Athens', 'Berlin', 'London'),
pop_mil = c(2.1, 0.6, 3.6, 9.0)
)
# Alphabetical by city
df[order(df$city), ]
# Reverse alphabetical
df[order(df$city, decreasing = TRUE), ]Resetting Row Numbers After Sort
After sorting, the row names reflect original positions (e.g., 3, 1, 4, 2). To reset them to sequential integers starting from 1, set row.names(df) <- NULL or wrap the result in data.frame().
df <- data.frame(
x = c(30, 10, 20),
y = c('c', 'a', 'b')
)
sorted <- df[order(df$x), ]
cat('Before reset:\n'); print(sorted)
row.names(sorted) <- NULL
cat('After reset:\n'); print(sorted)Sorting with NA Values
When a sort column contains NA, order() puts them at the end by default. Use na.last = FALSE to move NA rows to the top, or filter them out first.
df <- data.frame(
name = c('Alice', 'Bob', 'Carol', 'Dave'),
score = c(85, NA, 92, NA)
)
cat('NAs last (default):\n')
print(df[order(df$score), ])
cat('NAs first:\n')
print(df[order(df$score, na.last = FALSE), ])dplyr::arrange() as a Modern Alternative
The dplyr package provides arrange() as a cleaner alternative. While dplyr is not base R, knowing the syntax helps you read modern R code. Note: isRunnable is true here only to show the syntax — dplyr must be installed to run it.
# dplyr::arrange() syntax (requires dplyr installed)
# library(dplyr)
# df |> arrange(salary) # ascending
# df |> arrange(desc(salary)) # descending
# df |> arrange(dept, desc(salary)) # multi-column
# Equivalent base R:
df <- data.frame(dept=c('A','B','A'), salary=c(50,70,60))
df[order(df$dept, -df$salary), ]Sorting Factors by Level Order
Factor columns sort by their level order, not alphabetically. This lets you define a custom sort order by setting factor levels explicitly before sorting.
df <- data.frame(
priority = factor(c('Low', 'High', 'Medium', 'High', 'Low'),
levels = c('Low', 'Medium', 'High')),
task = c('T1', 'T2', 'T3', 'T4', 'T5')
)
# Sorts by factor level (Low < Medium < High)
df[order(df$priority), ]Sorting and Selecting Top Rows
A common pattern is to sort a data frame and then take the top N rows with head(), or the bottom N with tail(). This is the base-R equivalent of SQL's ORDER BY ... LIMIT N.
df <- data.frame(
product = c('A', 'B', 'C', 'D', 'E'),
revenue = c(1200, 4500, 890, 3100, 2750)
)
# Top 3 by revenue
top3 <- head(df[order(-df$revenue), ], 3)
row.names(top3) <- NULL
print(top3)In-Place Sort vs Assigned Sort
Sorting does not modify the original data frame — it returns a new one. Always assign the result to a variable (either a new one or overwrite the original). Overwriting the original is fine when you are done with the unsorted version.
df <- data.frame(
x = c(3, 1, 4, 1, 5, 9),
y = c('c', 'a', 'd', 'b', 'e', 'i')
)
# Safe: assign to new variable
df_sorted <- df[order(df$x), ]
# Or overwrite original:
df <- df[order(df$x), ]
row.names(df) <- NULL
print(df)Complete Sorting Workflow
Here is a complete, realistic data frame sorting workflow: sort employees by department name ascending and then by salary descending, reset row indices, and display the result cleanly.
employees <- data.frame(
name = c('Alice', 'Bob', 'Carol', 'Dave', 'Eve'),
dept = c('IT', 'HR', 'IT', 'HR', 'IT'),
salary = c(85000, 58000, 92000, 63000, 78000)
)
result <- employees[order(employees$dept, -employees$salary), ]
row.names(result) <- NULL
print(result)Quick Check
How do you sort a data frame df by a numeric column df$salary in descending order using base R?
Sorting Data Frames: Key Takeaways
Key takeaways for sorting data frames:
- Base R idiom:
df[order(df$col), ] - Descending numeric: negate with
-insideorder(-df$col) - Character descending: use
decreasing = TRUEargument - Multi-column:
order(df$a, df$b)— secondary sort breaks ties - Factors sort by their defined level order, not alphabetically
- Reset row names with
row.names(df) <- NULLafter sorting - Modern alternative:
dplyr::arrange()withdesc()for descending
df <- data.frame(
name = c('Zara', 'Ana', 'Bob', 'Ana'),
score = c(90, 85, 92, 88)
)
# Sort by name asc, score desc
result <- df[order(df$name, -df$score), ]
row.names(result) <- NULL
print(result)Frequently asked questions
Is the “Sorting Data Frames by Column” lesson free?
Yes — the full text of “Sorting Data Frames by Column” is free to read here on the web, and the R Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the R Academy course, upgrade to CoddyKit PRO.
What will I learn in “Sorting Data Frames by Column”?
Sort entire data frames using order() and dplyr's arrange(). You practise R Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start R Academy?
No prior experience is required. R Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Sorting Data Frames by Column” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this R Academy lesson?
Yes. Every R Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Sorting Vectors with sort()
- order() for Flexible Ordering
- Ranking Values with rank()
- Sorting Data Frames by Column