https://github.com/chrismuir/anagrams
R pkg for detecting anagrams
https://github.com/chrismuir/anagrams
anagram anagrams rcpp rstats
Last synced: over 1 year ago
JSON representation
R pkg for detecting anagrams
- Host: GitHub
- URL: https://github.com/chrismuir/anagrams
- Owner: ChrisMuir
- Created: 2018-02-18T19:05:09.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2018-10-10T12:27:07.000Z (almost 8 years ago)
- Last Synced: 2025-01-25T19:09:47.141Z (over 1 year ago)
- Topics: anagram, anagrams, rcpp, rstats
- Language: C++
- Homepage:
- Size: 336 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.Rmd
Awesome Lists containing this project
README
---
output:
github_document: default
html_document: default
---
```{r, echo = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
```
```{r message=FALSE, warning=FALSE, error=FALSE, include=FALSE}
options(width = 120)
```
# anagrams
[](https://travis-ci.org/ChrisMuir/anagrams)
`anagrams` is a super simple R package providing a function for comparing character vectors and determining if strings are [anagrams](https://en.wikipedia.org/wiki/Anagram) of one another. The project was inspired by [this](http://www.programmingr.com/content/simple-anagram-finder-using-r/) blog post on finding anagrams in R. The package uses C++ and [Rcpp](https://CRAN.R-project.org/package=Rcpp) for speed.
If you're interested in anagrams and R, be sure to check out [Romain Francois'](https://github.com/romainfrancois) package [anagram](https://github.com/romainfrancois/anagram) (and h/t to Romain for [pointing out](https://twitter.com/romain_francois/status/972754279164514304) some bottle-necks in my cpp code).
Also, thank you to [Mark van der Loo](https://github.com/markvanderloo) for pointing out that the [stringdist](https://github.com/markvanderloo/stringdist) package can be used to concisely determine same-length anagrams (and it's faster than the base R function I defined below!) I included the `stringdist` solution in the benchmarks below.
## Installation
Install from github with:
```{r eval = FALSE}
# install.packages("devtools")
devtools::install_github("ChrisMuir/anagrams")
```
## Example Usage
The exported function `is_anagram` takes as input a string and a character vector, and looks for anagrams of the string in the character vector.
```{r}
library(anagrams)
# Test for anagrams that are the same length as the input string.
is_anagram("stac", c("cats are great", "tacs", "frogs", "cats", "ts"))
# Use arg "value" to return the values that are anagrams.
is_anagram("stac", c("cats are great", "tacs", "frogs", "cats", "ts"), value = TRUE)
# Set arg "any_len" to TRUE to test for anagrams that are any length (either same length or sub-string).
is_anagram("stac", c("cats are great", "tacs", "frogs", "cats", "ts"), any_len = TRUE)
# Use arg "ignore_spaces" to make anagram searching insensitive to spaces.
is_anagram("s t a c", c("cats are great", "t acs", "frogs", "ca ts", "ts"), ignore_spaces = TRUE)
# Use arg "ignore_case" to make anagram searching insensitive to lower/upper case.
is_anagram("STAc", c("catS are great", "tacs", "frogs", "CaTS", "ts"), ignore_case = TRUE)
```
## Benchmarks
Let's create a simple, base R version of `is_anagram` that searches for same-length anagrams, and compare speeds.
```{r}
r_is_anagram <- function(string, terms) {
out <- rep(FALSE, length(terms))
terms_to_insp <- which(nchar(terms) == nchar(string))
if (length(terms_to_insp) == 0) {
return(out)
}
string_spl <- unlist(strsplit(string, "", fixed = TRUE), FALSE, FALSE)
str_counts <- vapply(string_spl, function(x) sum(string_spl == x), integer(1))
terms_spl <- strsplit(terms, "", fixed = TRUE)
out[terms_to_insp] <- vapply(terms_spl[terms_to_insp], function(x) {
anagram <- TRUE
for (char in string_spl) {
if (str_counts[char] != sum(x == char)) {
anagram <- FALSE
break
}
}
anagram
}, logical(1), USE.NAMES = FALSE)
out
}
# Test to make sure its output is identical to that of pkg function is_anagram.
identical(
r_is_anagram("stac", c("cats are great", "tacs", "frogs", "cats", "ts")),
is_anagram("stac", c("cats are great", "tacs", "frogs", "cats", "ts"))
)
```
And for completeness, here is a similar function that uses `stringdist::stringdist()` to find same-length anagrams.
```{r}
library(stringdist)
sd_is_anagram <- function(string, terms) {
out <- rep(FALSE, length(terms))
terms_to_insp <- which(nchar(terms) == nchar(string))
if (length(terms_to_insp) == 0) {
return(out)
}
out[terms_to_insp] <- stringdist(string, terms[terms_to_insp], method="qgram", q=1) == 0
out
}
# Test to make sure its output is identical to that of pkg function is_anagram.
identical(
sd_is_anagram("stac", c("cats are great", "tacs", "frogs", "cats", "ts")),
is_anagram("stac", c("cats are great", "tacs", "frogs", "cats", "ts"))
)
```
Now we'll compare speeds.
```{r message=FALSE, warning=FALSE, error=FALSE}
library(microbenchmark)
library(stringi)
# Test in which each element is shorter than the input string.
test_vect <- stringi::stri_rand_strings(100000, 3)
microbenchmark(
anagrams_pkg = is_anagram("cats", test_vect),
stringdist_pkg = sd_is_anagram("cats", test_vect),
base_r = r_is_anagram("cats", test_vect)
) -> mb
print(mb)
autoplot.microbenchmark(mb)
# Test in which each element is the same length as the input string.
test_vect <- stringi::stri_rand_strings(100000, 4)
microbenchmark(
anagrams_pkg = is_anagram("cats", test_vect),
stringdist_pkg = sd_is_anagram("cats", test_vect),
base_r = r_is_anagram("cats", test_vect)
) -> mb
print(mb)
autoplot.microbenchmark(mb)
# Test in which each element is an anagram of the input string.
test_vect <- rep("tacs", 100000)
microbenchmark(
anagrams_pkg = is_anagram("cats", test_vect),
stringdist_pkg = sd_is_anagram("cats", test_vect),
base_r = r_is_anagram("cats", test_vect)
) -> mb
print(mb)
autoplot.microbenchmark(mb)
# Test in which each element is a string with length between two and six chars.
test_vect <- stringi::stri_rand_strings(100000, 2:6)
microbenchmark(
anagrams_pkg = is_anagram("cats", test_vect),
stringdist_pkg = sd_is_anagram("cats", test_vect),
base_r = r_is_anagram("cats", test_vect)
) -> mb
print(mb)
autoplot.microbenchmark(mb)
# Test in which each element is a long string (nchar == 1000).
test_str <- stringi::stri_rand_strings(1, 1000)
test_vect <- stringi::stri_rand_strings(100000, 1000)
microbenchmark(
anagrams_pkg = is_anagram(test_str, test_vect),
stringdist_pkg = sd_is_anagram(test_str, test_vect),
base_r = r_is_anagram(test_str, test_vect)
) -> mb
print(mb)
autoplot.microbenchmark(mb)
```