Visit the reverse-string exercise on Exercism to read the full instructions and download the exercise files.
Dig Deeper
Split, reverse
Split-Reverse-Paste
reverse <- function(text) {
splits <- strsplit(text, "")[[1]]
reversed <- rev(splits)
paste(reversed, collapse = "")
}
or equivalently:
reverse <- function(text) {
paste(rev(strsplit(text, "")[[1]]), collapse = "")
}
Whether using intermediate variables or nested functions, the same three steps are applied:
- Convert the string to a vector of characters.
The
strsplit() fuction returns a list (in this case with only one element), so appending [[1]] extracts the desired vector.
- Reverse the vector with
rev().
- Paste the character vector back to a string.
We want no separator between the characters, so include the
collapse = "" parameter.
This is a simple approach which has worked since early versions of R, and is likely to appear high on internet searches.
Two weaknesses:
- It is relatively slow.
- It will only convert a single input string to an output string.
It fails when applied to vectors with more than one element.
UTF-8 reverse
Use UTF8 codes
reverse <- function(text) {
intToUtf8(rev(utf8ToInt(text)))
}
In this approach we go via an intermediate vector of character codes: UTF-8 in the general case, but for characters common in English these are the same as ASCII codes:
> utf8ToInt("abc")
[1] 97 98 99
UTF-8 codes are just integers, which R is highly optimized to handle.
Using codes instead of characters makes little difference for very short strings, nut by avoiding some overhead it can be significantly faster for large amounts of text.
Details will be included in the Performance article.
In summary, reversing about 24k of text was about 10x faster with UTF-8 codes than characters.
Syntax options
See split-reverse for a discussion of intermediate variables vs nested functions.
See native-pipes for a functional approach using pipes.
The same choices are possible for UTF8-reverse, and pipes are probably preferred (in recent versions of R), representing a good balance of terseness and readability:
reverse <- function(text) {
utf8ToInt(text) |>
rev() |>
intToUtf8()
}
Native pipes
Native Pipes
reverse <- function(text) {
strsplit(text, "")[[1]] |>
rev() |>
paste(collapse = "")
}
From R 4.1.0 (introduced May 2021), the base language has native pipes, allowing a syntax more typical of functional languages such as F#.
For code such as a() |> b(), the result of a() automatically becomes the first parameter of b(), so this is another way of writing b(a()).
Note that the pipe operator in R needs a function call such as rev() on the right hand side, not a function name such as rev.
We must include the parentheses.
This syntax contrasts with some other languages that use pipes, and is a fairly common source of confusion.
The underlying approach in the above code is the same as split-reverse.
Pipes could similarly be used for UTF8-reverse:
reverse <- function(text) {
utf8ToInt(text) |>
rev() |>
intToUtf8()
}
Pipes give a good balance of terseness and readability when chaining together a series of operations, so they have become very popular among R programmers.
Before R 4.1.0, the only way to use pipes was with the %>% operator from the magrittr library.
This is still available and has some advanced features not implemented in native pipes.
However, native pipes are significantly simpler, require no library import, and are now preferred for most purposes.
Source: Exercism r/reverse-string