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 s
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.
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(' ');
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.
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.
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))
);
}
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.