dplyr ends_with() in R: Select Columns by Suffix

The ends_with() helper in dplyr selects columns whose names END WITH a given string. It is the suffix-based mirror of starts_with().

⚡ Quick Answer
df |> select(ends_with("_2024"))           # all columns ending with "_2024"
df |> select(ends_with("_pct"))            # percentage columns
df |> select(ends_with("X", ignore.case = FALSE))
df |> mutate(across(ends_with("_total"), as.integer))
df |> select(-ends_with("_temp"))           # drop suffix-matched

Need explanation? Read on for examples and pitfalls.

📊 Is ends_with() the right tool?
STARTcolumns whose names end with Xends_with("X")start with Xstarts_with("X")contain X anywherecontains("X")regexmatches("regex")ignore casedefault is TRUE; set FALSE for strictcombineends_with("_pct") & where(is.numeric)

What ends_with() does in one sentence

ends_with(match) selects columns whose names END with the literal string match. Used inside dplyr verbs that support tidyselect.

Syntax

ends_with(match, ignore.case = TRUE, vars = NULL). Case-insensitive by default.

Run live
Run live, no install needed. Every R block on this page runs in your browser. Click Run, edit the code, re-run instantly. No setup.
RAll columns ending in 'Length'
library(dplyr) iris |> select(ends_with("Length")) |> head(3) #> Sepal.Length Petal.Length #> 1 5.1 1.4 #> 2 4.9 1.4 #> 3 4.7 1.3

  
Tip
Use ends_with for naming conventions like _2024, _pct, _total, _id. Common in tidy data with descriptive suffixes.

Five common patterns

1. Select by suffix

RAll _2024 columns
df |> select(ends_with("_2024"))

  

2. Apply transformation by suffix

RScale all _pct columns
df |> mutate(across(ends_with("_pct"), ~ .x / 100))

  

3. Drop by suffix

RRemove all _temp columns
df |> select(-ends_with("_temp"))

  

4. Strict matching

RCase-sensitive
df <- tibble(score_X = 1, score_x = 2) df |> select(ends_with("X", ignore.case = FALSE)) #> score_X

  

5. Combine with other helpers

RSuffix AND numeric
df |> select(ends_with("_total") & where(is.numeric))

  
Key Insight
ends_with() matches LITERAL strings. For regex suffix patterns, use matches("_\\d{4}$") to match _ followed by 4 digits at end.

ends_with() vs starts_with() vs contains() vs matches()

Helper Matches
starts_with("x") Names starting with "x"
ends_with("y") Names ending with "y"
contains("ab") Names containing "ab"
matches("regex") Regex match

Use ends_with for suffix-based; starts_with for prefix; contains for substring; matches for regex.

A practical workflow

Use ends_with for time-stamped or unit-suffixed columns.

RInteractive R
sales |> mutate(across(ends_with("_revenue"), ~ .x / 1000)) |> rename_with(~ sub("_revenue", "_revenue_k", .x), ends_with("_revenue"))

  

Scale and rename simultaneously.

For period comparisons:

RInteractive R
df |> mutate(diff = rowSums(across(ends_with("_2024"))) - rowSums(across(ends_with("_2023"))))

  

Common pitfalls

Pitfall 1: confusing ends_with with starts_with. Easy typo. Make sure you're matching the right side of the column name.

Pitfall 2: case-sensitivity default. Like starts_with, ends_with is case-insensitive by default. Pass ignore.case = FALSE for strict.

Warning
ends_with() accepts a single string or character vector. Vector means "OR": ends_with(c("_a","_b")) matches names ending with either suffix.

Try it yourself

Try it: Select all iris columns ending with "Width". Save to ex_widths.

RYour turn: width columns
ex_widths <- iris |> # your code here names(ex_widths) #> Expected: c("Sepal.Width", "Petal.Width")

  
Click to reveal solution
RSolution
ex_widths <- iris |> select(ends_with("Width")) names(ex_widths) #> [1] "Sepal.Width" "Petal.Width"

  

Explanation: Two iris columns end with "Width".

After mastering ends_with, look at:

  • starts_with(): prefix mirror
  • contains(): substring
  • matches(): regex
  • everything(): all remaining
  • where(): predicate-based

FAQ

What does ends_with do in dplyr?

ends_with(match) selects columns whose names end with the string match. Tidyselect helper for suffix matching.

Is ends_with case-sensitive?

No, by default it is case-insensitive. Pass ignore.case = FALSE for strict matching.

Can ends_with take multiple suffixes?

Yes. ends_with(c("_a","_b")) matches names ending with either suffix.

What is the difference between ends_with and matches?

ends_with is literal; matches is regex. ends_with(".csv") matches the literal ".csv"; matches("\\.csv$") does the same with regex.

How do I drop columns by suffix?

select(-ends_with("_temp")). Minus inverts the selection.