How to Extend Letters Past 26 Characters E.G., Aa, Ab, Ac...

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:


Sample Image


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



Leave a reply



Submit