30-Day Course
Clinical SAS → R
Day 8 of 30·Data Manipulation

Sorting & De-duplication: arrange() & distinct()

PROC SORT — including NODUPKEY and BY-group firsts — the dplyr way.

Learning objectives

  • 1Sort with arrange() and desc().
  • 2Remove duplicates with distinct().
  • 3Reproduce FIRST./LAST. logic with group_by() + slice().
  • 4Understand stable sorting behavior.

Key SAS® → R comparison

TaskSAS®R
Sort ascendingproc sort; by age;arrange(df, age)
Sort descendingby descending age;arrange(df, desc(age))
Remove dupsnodupkey by usubjid;distinct(df, usubjid, .keep_all=TRUE)
First per groupfirst.usubjidgroup_by()+slice(1)
Last per grouplast.usubjidgroup_by()+slice_tail(n=1)

Code examples

Last visit per subject
SAS®
proc sort data=vs; by usubjid visitnum; run;
data last; set vs;
  by usubjid;
  if last.usubjid;
run;
R
last <- vs |>
  arrange(usubjid, visitnum) |>
  group_by(usubjid) |>
  slice_tail(n = 1) |>
  ungroup()

Note: Always ungroup() when done so later operations don't silently run by group.

Explanation

arrange() sorts and is stable, so ties retain their original order. distinct() handles NODUPKEY, optionally keeping all columns with .keep_all = TRUE.

The FIRST./LAST. idiom becomes group_by() plus slice() — explicit, composable, and free of the positional sort dependencies that make DATA-step BY processing error-prone.

Practice exercise

From a VS dataset, keep the last record per subject by visit, and separately produce a de-duplicated subject-level list of USUBJID and ARM.