Reputation: 6648
I need to increment a string from.. let's say aaa
to zzz
and write every incrementation in the console (is incrementation even a word?). It would go something like this:
aaa
aab
aac
...
aaz
aba
abb
abc
...
abz
aca
acb
And so on. So far I have incremented a single letter by doing this:
String.prototype.replaceAt = function(index, character) {
return this.substr(0, index) + character + this.substr(index+character.length);
}
string = "aaa";
string = string.replaceAt(2, String.fromCharCode(string.charCodeAt(2) + 1));
//string == "aab"
However, I am lost when it comes to the final letter being z
and it should then increment letter 2 (index 1) and reset the last letter to be a
.
Does anyone have or know a smart solution to this? Thanks!
Upvotes: 13
Views: 21892
Reputation: 1
Gets A-Z, AA-ZZ, AAA-ZZZ etc. until the number of cycles is up.
function createList(maxCycles) {
if (typeof maxCycles != "number") {
console.log("number expected");
return;
}
const alphaLen = 26;
const alpha = ["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"];
let list = [alpha];
// go through all cycles
for (let cycleNo = 1; cycleNo < maxCycles; cycleNo++) {
list[cycleNo] = [];
pastCollection = list[cycleNo - 1];
pastLen = pastCollection.length;
for (let i = 0; i < pastLen; i++) {
for (let j = 0; j < alphaLen; j++) {
// use past item then add a letter of the alphabet at the end
list[cycleNo].push(pastCollection[i] + alpha[j]);
}
}
}
return list;
}
(function(maxCycles) {
console.log(createList(maxCycles));
})(3);
Upvotes: 0
Reputation: 81
I just want to provide an alternative answer to @procrastinator's (since I can't comment on the answer because I don't have enough points on Stackoverflow). His answer seems like the most generic approach but I can't help and notice that after "z" comes "ba" when op expect it to be "aa". Also, this follows how Excel name it's columns.
Here is the code with corrections:
function s2n(s) {
var pow, n = 0, i = 0;
while (i++ < s.length) {
pow = Math.pow(26, s.length - i);
var charCode = s.charCodeAt(i - 1) - 96;
n += charCode * pow;
}
return n;
}
function n2s(n) {
var s = '';
var reduce = false;
if (n === undefined) {
n = 0;
} else {
n--;
}
while (n !== undefined) {
s = String.fromCharCode(97 + n % 26) + s;
n = Math.floor(n / 26);
if (n === 0) {
n = undefined;
} else {
n--;
}
}
return s;
}
Instead of starting from 0, this will consider 1 to be "a", 26 to be "z", 27 to be "aa" and so on.
Upvotes: 1
Reputation:
This function gives 3 characters based on a number:
function n2s (n) {
var s = '';
while (s.length < 3) {
s = String.fromCharCode(97 + n % 26) + s;
n = Math.floor(n / 26);
}
return s;
}
To print strings from "aaa" to "zzz":
var zzz = Math.pow(26, 3) - 1;
for (var n = 0; n <= zzz; n++) {
console.log(n2s(n));
}
function n2s (n) {
var s = '';
while (s.length < 3) {
s = String.fromCharCode(97 + n % 26) + s;
n = Math.floor(n / 26);
}
return s;
}
var result = [];
var zzz = Math.pow(26, 3) - 1;
for (var n = 0; n <= zzz; n++) {
result.push(n2s(n));
}
document.body.innerHTML = result.join(' ');
Ask for details :-)
Improvements
Performances compared to the accepted answer: http://jsperf.com/10-to-26.
// string to number: s2n("ba") -> 26
function s2n(s) {
var pow, n = 0, i = 0;
while (i++ < s.length) {
pow = Math.pow(26, s.length - i);
n += (s.charCodeAt(i - 1) - 97) * pow;
}
return n;
}
// number to string: n2s(26) -> "ba"
function n2s(n) {
var s = '';
if (!n) s = 'a';
else while (n) {
s = String.fromCharCode(97 + n % 26) + s;
n = Math.floor(n / 26);
}
return s;
}
// pad("ba", 4) -> "aaba"
function pad (s, n) {
while (s.length < n) s = 'a' + s;
return s;
}
Usage:
var from = s2n('azx');
var to = s2n('baa');
for (var n = from; n <= to; n++) {
console.log(pad(n2s(n), 3));
}
Output:
azx
azy
azz
baa
Recursivity
Probably less efficient in terms of memory use or computation time: https://jsperf.com/10-to-26/4.
function n2s(n) {
var next = Math.floor(n / 26);
return (
next ? n2s(next) : ''
) + (
String.fromCharCode(97 + n % 26)
);
}
function s2n(s) {
return s.length && (
(s.charCodeAt(0) - 97)
) * (
Math.pow(26, s.length - 1)
) + (
s2n(s.slice(1))
);
}
Upvotes: 10
Reputation: 378
I used your code and added a few new functions.
String.prototype.replaceAt = function(index, character) {
return this.substr(0, index) + character + this.substr(index+character.length);
}
String.prototype.incrementAt = function(index) {
var newChar = String.fromCharCode(this.charCodeAt(index) + 1); // Get the next letter that this char will be
if (newChar == "{") { // If it overflows
return this.incrementAt(index - 1).replaceAt(index, "a"); // Then, increment the next character and replace current char with 'a'
}
return this.replaceAt(index, newChar); // Replace this char with next letter
}
String.prototype.increment = function() {
return this.incrementAt(this.length - 1); // Starts the recursive function from the right
}
console.log("aaa".increment()); // Logs "aab"
console.log("aaz".increment()); // Logs "aba"
console.log("aba".increment()); // Logs "abb"
console.log("azz".increment()); // Logs "baa"
This incrementAt
function is recursive and increments the character it is currently on. If in the process it overflows (the character becomes {
which is after z
) it calls incrementAt
on the letter before the one it is on.
The one problem with this code is if you try to increment zzz
you get aaaz
. This is because it is trying to increment the -1th character which is the last one. If I get time later I'll update my answer with a fix.
Note that this solution will work if you have a different length string to start off. For example, "aaaa" will count up to "zzzz" just fine.
Upvotes: 1
Reputation: 290
I took a different approach with this, using a permutations function which recursively generated all the possible permutations one could generate using characters from an array repeated n times. The code looks like this.
//recursively generates permutations
var permutations = function (li, rep) {
var i, j, next, ret = [];
// base cases
if (rep === 1) {
return li;
}
if (rep <= 0) {
return [];
}
// non-base case
for (i = 0; i < li.length; i += 1) {
// generate the next deepest permutation and add
// the possible beginnings to those
next = permutations(li, rep-1);
for (j = 0; j < next.length; j += 1) {
ret.push(li[i] + next[j]);
}
}
return ret;
};
// returns an array of numbers from [start, end)
// range(10, 14) -> [10, 11, 12, 13]
var range = function (start, end) {
var i, ret = [];
for (i = start; i < end; i+= 1) {
ret.push(i);
}
return ret;
};
// generates letters ('abcd...')
var letters = String.fromCharCode.apply(this, range('a'.charCodeAt(0), 'z'.charCodeAt(0)+1));
// calls the function itself, and .join's it into a string
document.body.innerHTML = (permutations(letters, 3)).join(' ');
Upvotes: 2
Reputation: 906
This will function will do the part of incrementing the string to next sequence
function increment(str){
var arr = str.split("");
var c;
for(var i=arr.length-1; i>=0; i--){
c = (arr[i].charCodeAt(0)+1)%123;
arr[i] = String.fromCharCode(c==0?97:c);
if(c!=0)break;
}
return arr.join("");
}
I was working on another solution to increment by any number and also in reverse direction. The code still has some bugs, but just putting it up here to receive some suggestions. pass in negative numbers to go in reverse direction. Code fails for some edge cases, for eg: when character is 'a' and num is negative number
function jumpTo(str,num){
var arr = str.split("");
var c;
for(var i=arr.length-1; i>=0; i--){
c = (arr[i].charCodeAt(0)+1)%123;
c += c==0?97+num-1:num-1;
arr[i] = String.fromCharCode(c==0?97:c);
if(c!=0)break;
}
return arr.join("");
}
Upvotes: 0
Reputation: 10209
The example below can work from a...a
to z...z
.
String.prototype.replaceAt = function(index, character) {
return this.substr(0, index) + character + this.substr(index + character.length);
}
String.prototype.inc = function() {
var stop = 'z';
var start = 'a';
var currentIndex = this.length - 1;
var string = this.replaceAt(currentIndex, String.fromCharCode(this.charCodeAt(currentIndex) + 1));
for (var i = string.length - 1; i > 0; i--) {
if (string[i] == String.fromCharCode(stop.charCodeAt(0) + 1)) {
string = string.replaceAt(i - 1, String.fromCharCode(string.charCodeAt(i - 1) + 1));
string = string.replaceAt(i, String.fromCharCode(start.charCodeAt(0)));
}
}
return string;
}
var string = "aaa";
var allStrings = string;
while(string != "zzz") {
string = string.inc();
allStrings += " " + string;
}
document.getElementById("current").innerHTML = allStrings;
<div id="current"></div>
Upvotes: 0
Reputation: 13828
Interesting approach with Number#toString
:
var n = 13330
var ns = []
for(var i = 0; i < 26; i++) {
for(var j = 0; j < 26; j++) {
for(var k = 0; k < 26; k++) {
ns.push(n.toString(36))
n++
}
n += 10 // jump from '(x)0' to '(x+1)a', etc.
}
n += 360 // jump from '(x)0a' to '(x)aa', etc.
}
console.log(ns) // the strings you wanted
Upvotes: 0
Reputation: 1402
Took a bit of algorithmic approach. This function takes initial string as an argument, increments next possible char in alphabet and at last returns the result.
function generate(str)
{
var alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
var chars = [];
for(var i = 0; i < str.length; i++)
{
chars.push(alphabet.indexOf(str[i]));
}
for(var i = chars.length - 1; i >= 0 ; i--)
{
var tmp = chars[i];
if(tmp >= 0 && tmp < 25) {
chars[i]++;
break;
}
else{chars[i] = 0;}
}
var newstr = '';
for(var i = 0; i < chars.length; i++)
{
newstr += alphabet[chars[i]];
}
return newstr;
}
Here is the loop helper function which accepts the initial string to loop through and generate all combinations.
function loop(init){
var temp = init;
document.write(init + "<br>");
while(true)
{
temp = generate(temp);
if(temp == init) break;
document.write(temp + "<br>");
}
}
Usage: loop("aaa");
Upvotes: 4
Reputation: 6052
Let's try this approach. It's a straight loop which produces the complete sequence from aaa,aab,aac,.....,xzz,yzz,zzz
function printSeq(seq){
console.log(seq.map(String.fromCharCode).join(''));
}
var sequences = [];
(function runSequence(){
var seq = 'aaa'.split('').map(function(s){return s.charCodeAt(0)});
var stopCode = 'z'.charCodeAt(0);
do{
printSeq(seq);
sequences.push(seq.map(String.fromCharCode).join(''));
if (seq[2]!=stopCode) seq[2]++;
else if (seq[1]!=stopCode) seq[1]++;
else if (seq[0]!=stopCode) seq[0]++;
}while (seq[0]<stopCode);
printSeq(seq);
sequences.push(seq.map(String.fromCharCode).join(''));
})();
The results are displayed in the console and also you'll get a complete sequence stored in sequence
array. Hope this is readable and helpful.
Upvotes: 1
Reputation: 35670
Treat the string like it's a base 36 number.
Convert it to decimal, add 1, convert back to base 36, and replace any zeroes with the letter 'a':
var str= 'aaa',
s= str;
while(str!=='zzz') {
str= ((parseInt(str, 36)+1).toString(36)).replace(/0/g,'a');
s+= ' '+str;
}
document.body.innerHTML= s;
Upvotes: 27
Reputation: 126
Assuming you will always have 3 letters (or any other set number of letters), off the top of my head I would think to:
Have separate variables for each letter, so instead of:
string = "aaa";
Have:
string1 = "a";
string2 = "a";
string3 = "a";
Then increment the one you need at each iteration. This will take a little trial and error probably, and looks like you're going from the right over to the left, so roughly:
if(string3 != "z"){
// Increment string 3 by a letter
}else if(string2 != "z"){
// Increment string 2 by a letter
}else if (string1 != "z"){
// Increment string 1 by a letter
}else{
// What ever you want to do if "zzz"
}
I didn't test that but it would be something close.
Then
string = string1 + string2+ string3
Now you are left with a single variable like before which you can do what you intended with (i.e. output etc.)
You could also do this with a string array, which would make it easier to have a changing amount of letters, and would need a little more code to count the array length and stuff, but I'd want to get it working at least statically first like above.
Upvotes: 0