nrow()
nrow(x) nrow() returns the number of rows in a matrix, array, or data frame. It returns NULL for atomic vectors since vectors have no dimensions.
Syntax
nrow(x)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
x | matrix, array, data frame, or NULL | , | Input object to get row count from |
Examples
Basic usage with a matrix
The most common application of nrow() is checking matrix dimensions. When you create a matrix with matrix(), the nrow argument specifies the row count, and nrow() retrieves it later. This is useful for verifying that reshaping or subsetting operations produced the expected dimensions.
# Create a 3x4 matrix
mat <- matrix(1:12, nrow = 3, ncol = 4)
nrow(mat)
# [1] 3
Working with data frames
For data frames, nrow() returns the number of observations — the dataset’s row count. This is the standard way to check how many records a data frame contains after loading from a CSV, filtering, or joining. Unlike length(), which returns the number of columns for a data frame, nrow() always gives the observation count.
df <- data.frame(
name = c("Alice", "Bob", "Charlie"),
age = c(25, 30, 35),
score = c(85, 92, 78)
)
nrow(df)
# [1] 3
Using with NULL and vectors
A key behavior to remember: nrow() returns NULL for objects without a row dimension, including vectors and NULL itself. This distinguishes it from functions that throw errors on non-tabular input. When writing generic helper functions, use NROW() instead, which treats vectors as single-column matrices and returns length(x) rather than NULL.
# NULL has no dimensions
nrow(NULL)
# NULL
# Vectors have no dimensions
vec <- 1:10
nrow(vec)
# NULL
Common patterns
Loop over rows
nrow() is the natural choice when iterating over matrix rows with a for loop. Using 1:nrow(mat) as the loop index visits each row in sequence, and mat[i, ] extracts the i-th row for processing. This pattern works equally well with data frames, though for loops over data frame rows are less common in idiomatic R than apply-family alternatives.
mat <- matrix(1:12, nrow = 3)
# Process each row
for (i in 1:nrow(mat)) {
print(mean(mat[i, ]))
}
Check if object has rows
A common defensive pattern is wrapping nrow() in a helper that checks whether an object has a row dimension at all. Testing !is.null(nrow(x)) distinguishes matrices and data frames from vectors, which is useful when a function must accept multiple input types and branch on the result.
has_rows <- function(x) {
!is.null(nrow(x))
}
has_rows(matrix(1:4, 2, 2))
# [1] TRUE
has_rows(1:10)
# [1] FALSE
Get last row
nrow() combined with bracket indexing gives you the last row of a matrix or data frame: mat[nrow(mat), ]. This expression is self-documenting — it reads as “row number equal to the total number of rows.” The same pattern works for the last column with ncol() and for single-element access in either dimension.
mat <- matrix(1:12, nrow = 3, ncol = 4)
# Get last row
mat[nrow(mat), ]
# [1] 9 10 11 12
nrow() in practice
nrow() returns the number of rows in a matrix or data frame. For vectors, it returns NULL. For data frames, nrow(df) is the count of observations, making it the standard check for data size: cat("Loaded", nrow(df), "rows ").
In filtering operations, comparing nrow() before and after is the standard way to confirm how many rows were removed: n_before <- nrow(df); df <- df[condition, ]; cat("Removed", n_before - nrow(df), "rows "). The tidyverse equivalent nrow() works the same way on tibbles.
NROW() treats a vector as a single-column matrix, returning its length rather than NULL. This is useful in generic functions: NROW(x) returns the number of observations whether x is a vector or a data frame.
nrow() is equivalent to dim(x)[1]. For checking whether a data frame is empty, nrow(df) == 0 is the standard idiom. After joining or filtering, always check nrow() to verify the operation worked as expected — an inner join that returns 0 rows is a common sign of a key mismatch.
nrow() returns the number of rows in a matrix or data frame. For a vector, it returns NULL. NROW() treats vectors as single-column matrices and returns length(), useful in generic functions that should accept both vectors and matrices. In a pipeline, nrow() is often used at the end as a quick sanity check: df |> filter(...) |> nrow() counts matching rows without materializing a full result.
nrow() returns the number of rows in a matrix or data frame. For vectors, it returns NULL. NROW() treats vectors as single-column matrices, returning length() — useful in generic functions that must accept both vectors and matrices without branching.
In pipelines, nrow() is a count assertion: df |> filter(active == TRUE) |> nrow() counts active rows without materializing extra columns. The equivalent dplyr approach is count(), which is more informative when grouped counts are needed, but nrow() is faster for a simple total.
After rbind() or bind_rows(), verifying nrow() confirms the append produced the expected row count. If a join unexpectedly multiplies rows, nrow(result) > nrow(original) catches the problem early.
nrow(NULL) returns NULL, not 0. Code that must handle NULL inputs should use NROW() or guard with is.null(). For matrices, nrow() is equivalent to dim(m)[1].
Verifying data integrity after filtering
# Load-like scenario: filter and check row counts
records <- data.frame(
id = 1:100,
status = sample(c("active", "inactive", "pending"), 100, replace = TRUE),
value = rnorm(100, mean = 50, sd = 15)
)
# Count before filtering
n_before <- nrow(records)
# Filter to active records only
active <- records[records$status == "active", ]
n_after <- nrow(active)
# Report the change
cat(sprintf("Filtered from %d to %d rows (removed %d)\n",
n_before, n_after, n_before - n_after))
# Filtered from 100 to 33 rows (removed 67)
# Safety: check the row count didn't vanish entirely
stopifnot(nrow(active) > 0)
This pattern of capturing nrow() before and after a filtering operation is the standard way to audit data pipeline steps. If the stopifnot guard triggers, it means the filter removed every row, which usually signals a mis-specified condition or unexpected values in the status column. For multiple sequential filters, recording row counts at each stage helps you identify exactly which step loses data — an approach far more informative than discovering the problem only at the final output.