Have you considered cut
? You can put custom breaks and labels for it.
breaks <- c(24, 29, 34)
labels <- paste(breaks[-length(breaks)] + 1, breaks[-1], sep = '-')
labels
#[1] "25-29" "30-34"
transform(df, age_cl = cut(age, breaks, labels))
# age age_cl age_cl_expected
#1 25 25-29 25-29
#2 26 25-29 25-29
#3 27 25-29 25-29
#4 28 25-29 25-29
#5 29 25-29 25-29
#6 30 30-34 30-34
#7 31 30-34 30-34
#8 32 30-34 30-34
#9 33 30-34 30-34
#10 34 30-34 30-34
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…