is there a way to extend LETTERS past 26 characters e.g., AA, AB, AC...?
Would 702 be enough?
LETTERS702 <- c(LETTERS, sapply(LETTERS, function(x) paste0(x, LETTERS)))
If not, how about 18,278?
MOAR_LETTERS <- function(n=2) {
n <- as.integer(n[1L])
if(!is.finite(n) || n < 2)
stop("'n' must be a length-1 integer >= 2")
res <- vector("list", n)
res[[1]] <- LETTERS
for(i in 2:n)
res[[i]] <- c(sapply(res[[i-1L]], function(y) paste0(y, LETTERS)))
unlist(res)
}
ml <- MOAR_LETTERS(3)
str(ml)
# chr [1:18278] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" ...
repeating vector of letters
It's not too difficult to piece together a quick function to do something like this:
myLetters <- function(length.out) {
a <- rep(letters, length.out = length.out)
grp <- cumsum(a == "a")
vapply(seq_along(a),
function(x) paste(rep(a[x], grp[x]), collapse = ""),
character(1L))
}
myLetters(60)
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l"
# [13] "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x"
# [25] "y" "z" "aa" "bb" "cc" "dd" "ee" "ff" "gg" "hh" "ii" "jj"
# [37] "kk" "ll" "mm" "nn" "oo" "pp" "qq" "rr" "ss" "tt" "uu" "vv"
# [49] "ww" "xx" "yy" "zz" "aaa" "bbb" "ccc" "ddd" "eee" "fff" "ggg" "hhh"
Create a list of sequential letters like in excel's header in R
In case if you are interested in base R solution, you can try this:
all <- expand.grid(LETTERS, LETTERS)
all <- all[order(all$Var1,all$Var2),]
out <- c(LETTERS, do.call('paste0',all))
The out will return 702 values as vectors, I believe you want to subset them until 559, so you can write: out[1:559].
To rename your columns you can use, where data_frame is your data frame name
names(data_frame) <- out[1:559]
One important note though, I am assuming here that you only wanted column with two characters not more than that.
A generic approach using gtools
comb <- lapply(1:3, function(x)gtools::permutations(26,x, LETTERS, repeats.allowed = TRUE))
## Using 3 for excel 3 combinations of alphabets
unlist(lapply(comb, function(x)do.call('paste0', data.frame(x,stringsAsFactors = FALSE))))
Some observations:
> out[1:50]
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K"
[12] "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V"
[23] "W" "X" "Y" "Z" "AA" "AB" "AC" "AD" "AE" "AF" "AG"
[34] "AH" "AI" "AJ" "AK" "AL" "AM" "AN" "AO" "AP" "AQ" "AR"
[45] "AS" "AT" "AU" "AV" "AW" "AX"
Convert numbers to letters beyond the 26 character alphabet
I think you're looking for something like this
function colName(n) {
var ordA = 'a'.charCodeAt(0);
var ordZ = 'z'.charCodeAt(0);
var len = ordZ - ordA + 1;
var s = "";
while(n >= 0) {
s = String.fromCharCode(n % len + ordA) + s;
n = Math.floor(n / len) - 1;
}
return s;
}
// Example:
for(n = 0; n < 125; n++)
document.write(n + ":" + colName(n) + "<br>");
Numeric to Alphabetic Lettering Function in R
Here are some alternatives:
1) encode Let b be the base. Here b = 26. Then there are b^k appendices having k letters
so for a particular appendix having number x it has n letters if n is the
smallest integer for which b + b^2 + ... + b^n >= x. The LHS of this inequality is a geometric series and therefore has a closed form solution. Replacing the LHS with that expression and solving the resulting equation for n gives the formula for n in the code below. Then we subtract all b^k terms from number for which k < n and use the APL-like encode
function found here (and elsewhere on the web). encode
does the base conversion giving digits
, a vector of digits in base base
. Finally add 1 to each digit and use that as a lookup into LETTERS
.
app2 <- function(number, base = 26) {
n <- ceiling(log((1/(1 - base) - 1 - number) * (1 - base), base = base)) - 1
digits <- encode(number - sum(base^seq(0, n-1)), rep(base, n))
paste(LETTERS[digits + 1], collapse = "")
}
sapply(1:29, app2) # test
giving:
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O"
[16] "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "AA" "AB" "AC"
Another test to try is:
sapply(1:60, app2, base = 3)
2) recursive solution Here is an alternative that works recursively. It computes the last letter of the Appendix number and then removes it and recursively computes the portion to its left.
app2r <- function(number, base = 26, suffix = "") {
number1 <- number - 1
last_digit <- number1 %% base
rest <- number1 %/% base
suffix <- paste0(LETTERS[last_digit + 1], suffix)
if (rest > 0) Recall(rest, base, suffix) else suffix
}
# tests
identical(sapply(1:29, app2r), sapply(1:29, app2))
## [1] TRUE
identical(sapply(1:60, app2r, base = 3), sapply(1:60, app2, base = 3))
## [1] TRUE
Convert sequence of integers 1, 2, 3, ... to corresponding sequence of strings A, B, C,
Several nice solutions were posted in the comments already. Only the solution posted by @Gregor here is currently giving the preferred solution by Ben.
However, the methods posted by @eddi, @DavidArenburg and @G.Grothendieck can be adapted to get the prefered outcome as well:
# adaptation of @eddi's method:
library(data.table)
n <- 29
sz <- ceiling(log(n)/log(26))
do.call(CJ, replicate(sz, c("", LETTERS), simplify = F))[-1, unique(Reduce(paste0, .SD))][1:n]
# adaptation of @DavidArenburg's method:
n <- 29
list(LETTERS, c(LETTERS, do.call(CJ, replicate((n - 1) %/% 26 + 1, LETTERS, simplify = FALSE))[, do.call(paste0, .SD)][1:(n-26)])[[(n>26)+1]]
# adaptation of @G.Grothendieck's method:
n <- 29
sz <- ceiling(log(n)/log(26))
g <- expand.grid(c('',LETTERS), rep(LETTERS, (sz-1)))
g <- g[order(g$Var1),]
do.call(paste0, g)[1:n]
All three result in:
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O"
[16] "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "AA" "AB" "AC"
Generating an alphabetic sequence in Java
My version implements Iterator and maintains an int counter. The counter values are translated to the corresponding string:
import com.google.common.collect.AbstractIterator;
class Sequence extends AbstractIterator<String> {
private int now;
private static char[] vs;
static {
vs = new char['Z' - 'A' + 1];
for(char i='A'; i<='Z';i++) vs[i - 'A'] = i;
}
private StringBuilder alpha(int i){
assert i > 0;
char r = vs[--i % vs.length];
int n = i / vs.length;
return n == 0 ? new StringBuilder().append(r) : alpha(n).append(r);
}
@Override protected String computeNext() {
return alpha(++now).toString();
}
}
Call next() on the Iterator to use it.
Sequence sequence = new Sequence();
for(int i=0;i<100;i++){
System.out.print(sequence.next() + " ");
}
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB AC AD AE
An implementation with better performance for larger sequences reuses the common prefix:
class SequencePrefix extends AbstractIterator<String> {
private int now = -1;
private String prefix = "";
private static char[] vs;
static {
vs = new char['Z' - 'A' + 1];
for(char i='A'; i<='Z';i++) vs[i - 'A'] = i;
}
private String fixPrefix(String prefix){
if(prefix.length() == 0) return Character.toString(vs[0]);
int last = prefix.length() - 1;
char next = (char) (prefix.charAt(last) + 1);
String sprefix = prefix.substring(0, last);
return next - vs[0] == vs.length ?
fixPrefix(sprefix) + vs[0] : sprefix + next;
}
@Override protected String computeNext() {
if(++now == vs.length) prefix = fixPrefix(prefix);
now %= vs.length;
return new StringBuilder().append(prefix).append(vs[now]).toString();
}
}
You'll get even better performance if you rewrite this basic algorithm with an implementation that works with arrays. (String.charAt, String.substring and StringBuffer have some overhead.)
How do I convert a number to a letter in Java?
Just make use of the ASCII representation.
private String getCharForNumber(int i) {
return i > 0 && i < 27 ? String.valueOf((char)(i + 64)) : null;
}
Note: This assumes that i
is between 1
and 26
inclusive.
You'll have to change the condition to i > -1 && i < 26
and the increment to 65
if you want i
to be zero-based.
Here is the full ASCII table, in case you need to refer to:
Edit:
As some folks suggested here, it's much more readable to directly use the character 'A'
instead of its ASCII code.
private String getCharForNumber(int i) {
return i > 0 && i < 27 ? String.valueOf((char)(i + 'A' - 1)) : null;
}
What is a method that can be used to increment letters?
Simple, direct solution
function nextChar(c) {
return String.fromCharCode(c.charCodeAt(0) + 1);
}
nextChar('a');
As others have noted, the drawback is it may not handle cases like the letter 'z' as expected. But it depends on what you want out of it. The solution above will return '{' for the character after 'z', and this is the character after 'z' in ASCII, so it could be the result you're looking for depending on what your use case is.
Unique string generator
(Updated 2019/05/09)
Since this answer has received so much visibility I've decided to expand it a bit beyond the scope of the original question to potentially help people who are stumbling on this from Google.
I find that what I often want is something that will generate sequential, unique strings in a certain character set (such as only using letters), so I've updated this answer to include a class that will do that here:
class StringIdGenerator {
constructor(chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
this._chars = chars;
this._nextId = [0];
}
next() {
const r = [];
for (const char of this._nextId) {
r.unshift(this._chars[char]);
}
this._increment();
return r.join('');
}
_increment() {
for (let i = 0; i < this._nextId.length; i++) {
const val = ++this._nextId[i];
if (val >= this._chars.length) {
this._nextId[i] = 0;
} else {
return;
}
}
this._nextId.push(0);
}
*[Symbol.iterator]() {
while (true) {
yield this.next();
}
}
}
Usage:
const ids = new StringIdGenerator();
ids.next(); // 'a'
ids.next(); // 'b'
ids.next(); // 'c'
// ...
ids.next(); // 'z'
ids.next(); // 'A'
ids.next(); // 'B'
// ...
ids.next(); // 'Z'
ids.next(); // 'aa'
ids.next(); // 'ab'
ids.next(); // 'ac'
Related Topics
Asymmetric Expansion of Ggplot Axis Limits
Assigning Null to a List Element in R
Merge Dataframes on Matching A, B and *Closest* C
Find Consecutive Values in Vector in R
Applying a Function to Each Row of a Data.Table
How to Select Non-Numeric Columns Using Dplyr::Select_If
Count Every Possible Pair of Values in a Column Grouped by Multiple Columns
Combining Low Frequency Counts
Removing Unused Factors from a Facet in Ggplot2
Sort a List of Nontrivial Elements in R
How to Extend Letters Past 26 Characters E.G., Aa, Ab, Ac...
Weird Characters Added to First Column Name After Reading a Toad-Exported CSV File
How to Handle Vectors Without Knowing the Type in Rcpp
Change the Number of Breaks Using Facet_Grid in Ggplot2
Numbers as Column Names of Data Frames
How to Create a World Map in R with Specific Countries Filled In
Count the Number of Unique Characters in a String
Gsub in R with Unicode Replacement Give Different Results Under Windows Compared with Unix