Going from dplyr to base: create a data frame of the first and last index for each level of a variable

Viewed 53

Asking how to go from dplyr to base may be a weird ask, especially since I love the tidyverse, but I think because I learned the tidyverse first, my grasp of base is far from masterful, and I need a base solution because the package I'm helping to develop doesn't want any tidyverse dependencies

Data (there are many more columns, but abbreviated for reprex sake):

sample.df <- tibble(batch = rep(c(1,2,3), c(4,5,6)))

Desire base equivalent of:

sample.df %>%
  mutate(rowid = row_number()) %>%
  group_by(batch) %>%
  summarize(idx_b = min(rowid),
            idx_e = max(rowid))

# A tibble: 3 x 3
# Groups:   batch [3]
  batch idx_b idx_e
  <dbl> <int> <int>
1     1     1     4
2     2     5     9
3     3    10    15
2 Answers

We create a sequence column in the data, use aggregate to get the range or min/max and convert the matrix column to regular data.frame column with do.call

out <- do.call(data.frame, aggregate(rowid ~ batch,
   transform(sample.df, rowid = seq_len(nrow(sample.df))), 
      FUN = function(x) c(b = min(x), e = max(x))))

Another base R option using unique + ave

unique(
  transform(
    sample.df,
    idx_b = ave(1:nrow(sample.df), batch, FUN = min),
    idx_c = ave(1:nrow(sample.df), batch, FUN = max)
  )
)

gives

   batch idx_b idx_c
1      1     1     4
5      2     5     9
10     3    10    15
Related