Create a sequence between two letters

I want to create a sequence between two letters let's say "b" and "f". So the output is

"b" "c" "d" "e" "f"

For numbers, we can do

2:6 #which gives output as 
[1] 2 3 4 5 6

Is there an easy way to do this with letters as well?

I have gone through Generate a sequence of characters from 'A'-'Z' but this produces all the letters and not sequence between specific letters.

My current solution is,

indx <- which(letters %in% c("b", "f")); 
letters[indx[1] : indx[2]]

#[1] "b" "c" "d" "e" "f"

This works but I am curious if there is an easy way to do this or a function in any of the package that I have missed?

Note: I do not want letters[2:6] as I do not know 2 and 6 beforehand. It could be between any two letters.


Solution 1:

This would be another base R option:

letters[(letters >= "b") & (letters <= "f")]
# [1] "b" "c" "d" "e" "f"

Solution 2:

You can create your own function:

`%:%` <- function(l, r) {
    intToUtf8(seq(utf8ToInt(l), utf8ToInt(r)), multiple = TRUE)
}

Usage:

"b" %:% "f"
# [1] "b" "c" "d" "e" "f"

"f" %:% "b"
# [1] "f" "e" "d" "c" "b"

"A" %:% "D"
# [1] "A" "B" "C" "D"

Solution 3:

Another option with match, seq and do.call:

letters[do.call(seq, as.list(match(c("b","f"), letters)))]

which gives:

[1] "b" "c" "d" "e" "f"

Making a function of this such that it works with both lower-case and upper-case letters:

char_seq <- function(lets) {
  switch(all(grepl("[[:upper:]]", lets)) + 1L,
         letters[do.call(seq, as.list(match(lets, letters)))],
         LETTERS[do.call(seq, as.list(match(lets, LETTERS)))])
}

the output of this:

> char_seq(c("b","f"))
[1] "b" "c" "d" "e" "f"

> char_seq(c("B","F"))
[1] "B" "C" "D" "E" "F"

This function can be extended with checks on the correctness of the input:

char_seq <- function(lets) {
  g <- grepl("[[:upper:]]", lets)
  if(length(g) != 2) stop("Input is not of length 2")
  if(sum(g) == 1) stop("Input does not have all lower-case or all upper-case letters")
  switch(all(g) + 1L,
         letters[do.call(seq, as.list(match(lets, letters)))],
         LETTERS[do.call(seq, as.list(match(lets, LETTERS)))])
}

resulting in proper error-messages when the input is not correct:

> char_seq(c("B"))
Error in char_seq(c("B")) : Input is not of length 2

> char_seq(c("b","F"))
Error in char_seq(c("b", "F")) : 
  Input does not have all lower-case or all upper-case letters

Solution 4:

Playing with UTF, something like:

intToUtf8(utf8ToInt("b"):utf8ToInt("f"), multiple = TRUE)
# [1] "b" "c" "d" "e" "f"