Making a star triangle using javascript function recursively - javascript

I am pretty new to programming, I am getting to know JavaScript, and I've just learned the notion of recursion. Now I am given a problem, to create a function (like const f = function(n) { }) and if we if we call the function with f(5), we should see:
*
***
*****
*******
*********
The number of vertical stars must be determined by the input.
I've got to use no for/while/do-while; recursion only to loop.
I've come up with this code to concatenate 5 stars
const f = function(n) {
if (n === 0) {
return "";
}
return "*" + f(n - 1);
};
console.log(f(5));
Though, I don't see how to make the triangle, what can I do?

You can use this code:
const f = function(chr, n) {
if (n === 0) {
return "";
}
return chr + f(chr, n - 1);
};
const g = function(max) {
const inner = function(n) {
if (n > 1) {
inner(n-1);
}
console.log(f(' ', max-n) + f('*', (n*2)-1));
};
inner(max);
};
g(5);

Please see and play the example below
function pyramid(n, row = 0, level = '') {
if (row === n) {
return
}
if (level.length === n * 2 - 1) {
console.log(level)
return pyramid(n, row + 1)
}
const midpoint = Math.floor((2 * n - 1) / 2)
let add;
if (midpoint - row <= level.length && midpoint + row >= level.length) {
add = '#'
} else {
add = ' '
}
pyramid(n, row, level + add)
}
pyramid(3)

You are on the right way with the
if (n === 0) ...
and the
f(n-1)
these are correct already.
Now you just need to output the correct number of stars in every function call. Look at string.repeat() for that.
If you want to see a complete solution and not just a hint: here is my solution.

function recursiveStar(n){
if(n === 0) return 0;
recursiveStar(n - 1);
return console.log('*'.repeat(n));
}
recursiveStar(5)

You can try this
function pyramid(n, row = 0) {
if (n === row) return;
let midpoint = Math.ceil((n + n - 1) / 2);
let str = "";
for (let j = 1; j <= n + n - 1; j++) {
if (j <= midpoint + row && j >= midpoint - row) str += "#";
else str += " ";
}
console.log(str);
pyramid(n, row + 1);
}
pyramid(5);

As this old question has recently been brought back up, here's an alternative version that treats the depth as constant and recurs on the row number:
const pyramid = (n, r = 0) =>
r > n - 1
? ''
: ' '.repeat ((n - 1 - r)) + '*'.repeat ((2 * r + 1)) + '\n' + pyramid (n, r + 1)
console .log (pyramid (5))
We keep n fixed, starting r at zero, and then recursively incrementing r until it's greater than n. In our base case, when n is 0 and r is 0, we get r > n - 1, and return an empty string. The recursive case proceeds by adding the right number of spaces, the the right number of starts to our first row, and calculating the remaining rows by incrementing r, and recurring.
const pyramid = (n, r = 0) =>
r > n - 1
? ''
: ' ' .repeat ((n - 1 - r)) + '*' .repeat ( (2 * r + 1)) + '\n' + pyramid (n, r + 1)
// `-----------------------' `------------------------' `--' `----------------'
// | | | |
// | | | +-- next rows
// | | +---------------- line break
// | +----------------------------------- asterisks
// +--------------------------------------------------------------- empty spaces
The only slight trickiness in that is the calculation of the correct number of stars and spaces. It's pretty easy to see that for pyramid (5), the spaces should decrease steadily from 4 down to 0 and the asterisks should increase from 1 up to 9. These are captured by the formulas n - 1 - r and 2 * r + 1 respectively.
This was originally for an assignment, and if that assignment didn't allow us to use String.prototype.repeat, then we could easily write our own recursive version in a function like this:
const repeat = (c, n) =>
n < 1 ? '' : c + repeat (c, n - 1)
const pyramid = (n, r = 0) =>
r > n - 1
? ''
: repeat (' ', (n - 1 - r)) + repeat ('*', (2 * r + 1)) + '\n' + pyramid (n, r + 1)

Related

codewars kata: "Is my friend cheating?" Passed all test but using bruteforce, If someone could help me optimize my code by using actual math maybe?

Here is my solution
export function removeNb (n:number):number[][] {
const total = n * (n+1) / 2;
for(let a = n; a > 1; a--){
for(let b = a-1 ;b > 1 ; b--){
if(total - b - a === b*a){
return [[b,a],[a,b]]
}
}
}
return []
}
The problem is this:
A friend of mine takes the sequence of all numbers from 1 to n (where
n > 0).
Within that sequence, he chooses two numbers, a and b.
He says that the product of a and b should be equal to the sum of all
numbers in the sequence, excluding a and b.
Given a number n, could you tell me the numbers he excluded from the
sequence?
The function takes the parameter: n (n is always strictly greater than
0) and returns an array of arrays.
The test cases are as follows:
removeNb(26); //[[15,21],[21,15]]
removeNb(101); //[[55,91],[91,55]]
removeNb(102); //[[70,73],[73,70]]
removeNb(110); //[[70,85],[85,70]]
Update
As Ike mentioned the previous solution doesn't take in account the fact that a and b both need to be less or equal to n so the solution should be updated like this : (b needs to be less then n, ie (total - a) / (a + 1) <= n ie (total - n) / (n + 1) <= a)
function removeNb(n: number) {
const total = n * (n + 1) / 2;
const t: [number, number][] = [];
for (let a = Math.ceil((total - n) / (n + 1)); a * a < total; a++) {
const b = (total - a) / (a + 1)
if (!(b % 1)) t.push([a,b],...(a === b ? [] : [[b,a]]))
}
return t
}
With a bit of maths we can check that tatal - a - b = a * b is equivalent to (total - a) / (a + 1) = b so we can deduce b from a and just check if it is an integer.
Also since a and b are exchangeable we can require b to be greater or equal a i.e (total - a) / (a + 1) >= a <=> total >= a * (a + 2) so we can require a² < total.
So your function can be optimized this way:
function removeNb(n: number) {
const total = n * (n + 1) / 2;
const t: [number, number][] = [];
for (let a = 1; a * a < total; a++) {
const b = (total - a) / (a + 1)
if (!(b % 1)) t.push([a,b],...(a === b ? [] : [[b,a]]))
}
return t
}

Not able to solve the power sum for all cases using recursion

I have written the code of this problem but it works for only 70% of the test cases. I can't figure out what is wrong with it. Please help.
Problem:-
Find the number of ways that a given integer, X, can be expressed as the sum of the Nth powers of unique, natural numbers in the range of [1,25] both inclusive.
Hint:-
The answer will be (1^2 + 3^2).
My code is not working for x = 100 and n = 2. The output should be 3 but it returns 33.
let x = 100;
let n = 2;
let num = 0;
let index = 1;
function power(x, n, num, index, ways = 0) {
if (x === num) {
return 1;
}
if (x < num) {
return 0;
}
for (let i = index; i <= 25; i++) {
ways += power(x, n, (num + ((i) ** n)), index + 1);
}
return ways;
}
console.log(power(x, n, num, index));
Your logic is almost right. But you're not properly removing duplicate values and ending up including things like 9^2 + 3^2 + 3^2 + 1^2 or 5^2 + 5^2 + 5^2 + 4^2 + 3^2.
You need to change the recursive index you pass. You shouldn't use your index parameter but your loop iterator, i:
let x = 100;
let n = 2;
let num = 0;
let index = 1;
function power(x, n, num, index, ways = 0) {
if (x === num) {
return 1;
}
if (x < num) {
return 0;
}
for (let i = index; i <= 25; i++) {
// ways += power(x, n, (num + ((i) ** n)), index + 1);
// v-^
ways += power(x, n, (num + ((i) ** n)), i + 1);
}
return ways;
}
console.log(power(x, n, num, index));
I figured this out fairly quickly by writing my own version of the function from scratch, and getting the exact same wrong result. I added some logging and realized the problem and was able to spot it quickly. This translated easily to your code.
But I think my function is cleaner, so I'm including it here. It does much the same logic, but in a cleaner functional manner:
const range = (lo, hi) =>
Array .from ({length: hi - lo + 1}, (_, i) => i + lo)
const sum = (ns) =>
ns .reduce ((a, b) => a + b, 0)
const countPowerSums = (n, p, i = 1) =>
n < 0
? 0
: n == 0
? 1
: sum (range (i, 25) .map (b => countPowerSums (n - b ** p, p, b + 1)))
console .log (countPowerSums (100, 2))

How to do a combined pyramid with stars and numbers together in a single pattern

Need a pyramid with numbers and stars and there are no examples to review.
*
* 0 *
* 1 0 1 *
* 0 1 0 1 0 *
* 1 0 1 0 1 0 1 *
Can I get some assistance with this?
This is what I have, but I can't figure out how to get the the numbers in there..
function displayPyramid(n) {
for (let i = 0; i < n; i++) {
let str = ''
let count = 0
// Spacing before each row
for (let j = 1; j < n - i; j++) {
str = str + ' '
}
// Row worth of data
const max = 2 * i + 1
for (let k = 1; k <= max; k++) {
str = str + '*'
}
console.log(str);
}
}
displayPyramid(5)
Here's the thought process to get the expected result:
All rows with even indices are called 'even rows' (0, 2, 4, 6, …)
All rows with uneven indices are called 'uneven rows' (1, 3, 5, 7, …)
All stars are either the first or the last column in any row
For all even rows, the even indices display 0s, the uneven indices display 1s
For all uneven rows, the uneven indices display 0s, the even indices display 1s
I added a function called getSymbol that performs the last three checks and returns the appropriate symbol. I also renamed you iterator variables for better readability.
function getSymbol(column, max, row) {
if (column === 0 || column === max - 1) { // if it is the first or last index within the row
return '*'
}
if (row % 2 === 0) { // if it is an uneven row
if (column % 2 === 0) { // if it is an even column
return '0';
}
return '1' // if it is an uneven column within that row
}
// if it's not an even row, it's an uneven row
if (column % 2 === 0) { // if it is an even column within that row
return '1';
}
return '0' // if it is an uneven column within that row
}
function displayPyramid(n) {
for (let row = 0; row < n; row++) {
let str = ''
let count = 0
// Spacing before each row
for (let spaces = 1; spaces < n - row; spaces++) {
str = str + ' '
}
// Row worth of data
const max = 2 * row + 1
for (let column = 0; column < max; column++) {
str = str + getSymbol(column, max, row)
}
console.log(str);
}
}
displayPyramid(5)
function displayPyramid(n) {
for (let i = 0; i < n; i++) {
let str = "";
let count = 0;
// Spacing before each row
let padCount = 2 * n - 2 * i - 1;
for (let j = 1; j < padCount; j++) {
str = str + " ";
}
// Row worth of data
const max = 2 * i + 1;
for (let k = 1; k <= max; k++) {
if (k === 1 || k === max) {
str = str + "* ";
} else {
str += (k % 2).toString() + " ";
}
}
console.log(str);
}
}
displayPyramid(5);
Let's first try to write a function for just one line of the pyramid, any line. We'll ignore the whitespace for now too.
Every line of the pyramid seems to follow a few simple rules:
All lines start with a *.
The 'inner sequence' is just alternating 1 and 0 a certain number of times.
There are 2*n - 1 digits in the inner sequence of each line, except the first.
Even lines (0, 2, 4, ...) begin the inner sequence with a 1.
Odd lines (1, 3, 5, ...) begin the inner sequence with a 0.
All lines end with an additional *, except the first.
In the rules above, everything can be determined from n. So our function only needs one argument:
function GetLine(n) {
// ...
}
We can also determine whether a line is even or odd, and how many characters the inner sequence has:
EvenLine = (n % 2 == 0);
Count = 2*n - 1;
Building the sequence between the two stars can be done with a simple for loop.
Putting that all together, we can build the following function.
function GetLine(n) {
// Create a string for the line that starts with a star
var Line = "*";
// Determine whether the line is even or odd
var EvenLine = (n % 2 == 0);
// Calculate the total number of ones and zeros in the line
var Count = (2 * n - 1);
// We need a variable to store whether the next character should be a one or zero
var One = EvenLine ? true : false; // Even lines start with 1, Odd starts with 0
// Repeat 'Count' times, alternating between ones and zeros
for (var i=0; i<Count; i++)
{
Line += One ? "1" : "0";
One = !One; // Toggle the bool value to alternate on the next iteration
}
// Only add a tail star if we're not on the first line
if (n > 0) Line += "*";
return Line;
}
When we call GetLine() with some consecutive numbers we can see that the pattern is mostly there:
console.log(GetLine(0));
console.log(GetLine(1));
console.log(GetLine(2));
*
*0*
*101*
Now all that needs to be done is insert the whitespace in two steps:
A space between each character.
The leading space to align the pyramid.
function printPyramid(s) {
for (var n=0; n<s; n++) {
// Get the line for n
var line = GetLine(n);
// This one-liner can be used to insert whitespace between each character
// split('') will explode the characters into an array
// join(' ') will turn the array back into a string with ' ' inbetween each element
line = line.split('').join(' ');
// Then we just add the necessary whitespace for alignment
// We need 2 * (s - n - 1) spaces in front of each line.
line = " ".repeat(s - n - 1) + line;
// Print the line
console.log(line);
}
}
Finally,
printPyramid(5);
*
* 0 *
* 1 0 1 *
* 0 1 0 1 0 *
* 1 0 1 0 1 0 1 *
const rows = 5;
const columns = 2 * rows - 1;
// create an array filled with " "
const array = Array(rows).fill().map( () => Array(columns).fill(" "));
// if r and c are the row and column indices of the array, then
// in each row place two askerisks where c = rows -1 ± r (if r is 0, there's only one asterisk)
// and alternating 1's (if c is odd) and 0's (if c is even) for all elements between columns rows - 1 - r and rows - 1 + r
const pyramid = array.map(function(row, r) {
return row.map(function(v, c) {
return c === rows - 1 - r || c === rows - 1 + r ? "*" : c > rows - 1 - r && c < rows - 1 + r ? c % 2 === 1 ? "1" : "0" : v;
});
});
// const pyramid = array.map( (row, r) => row.map( (v, c) => c === rows - 1 - r || c === rows -1 + r ? "*" : c > rows - 1 - r && c < rows - 1 + r ? c % 2 === 1 ? "1" : "0" : v))
function displayPyramid(n)
{
for (let i = 0; i < n; i++)
{
let str = ''
let count = 0
// Spacing before each row
for (let j = 1; j < n - i; j++)
{
str = str + ' '
}
// Row worth of data
const max = 2 * i + 1
str = str + '*'
const innerChars = ['0', '1'];
for (let k = 1; k < max; k++)
{
if (k === max - 1)
str += '*'
else
str += innerChars[(i % 2 + k) % 2];
}
console.log(str);
}
}
displayPyramid(5)
The main observations to make:
The first row we have no innner char
The second row begins with inner char 0
The third row begins with inner char 1 then alternates
The forth row begins with inner char 0 then alternate
We notice a pattern, even rows (or odd if zero based) begin with 0, and vice versa. Alternating pattern should hint to an array that we loop around.
I wasn't sure if you needed the spaces, or if you wanted to change the characters in the tree, so I added them as parameters.
If you want to have more than 2 elements in the array, and have the first element in the center, you can shift the array on every row, instead of reversing it.
function displayPyramid(n, charArray, withSpace) {
let charArrayOrdered = charArray
for (let i = 0; i < n; i++) {
let str = ''
let count = 0
// Spacing before each row
let withSpaceChar = ''
if(withSpace) {
withSpaceChar=' '
}
for (let j = 1; j < n - i; j++) {
str = str + ' ' + withSpaceChar
}
// Row worth of data
const max = 2 * i
charArrayOrdered = charArrayOrdered.reverse()
let charState = 0
for (let k = 0; k <= max; k++) {
let char = '*'
if(k!=0 && k !=max) {
char=charArrayOrdered[charState]
charState++
}
if(charState==charArrayOrdered.length){
charState=0
}
if(k!=max && withSpace) {
char = char+' '
}
str = str + char
}
console.log(str);
}
}
displayPyramid(5,[0,1], true)
You could do something like this but if in the middle is 0 or 1 will depend on the number you provided.
function build(n) {
let grid = ''
let total = n * 2;
for (let i = 0; i < n - 1; i++) {
let row = [];
let start = total / 2 - i - 1
let end = total / 2 + i
if (!i) grid += ' '.repeat(start + 1) + '*' + '\n'
for (let j = 0; j < total; j++) {
if (j < start) row.push(' ');
else if (j > end) row.push(' ');
else {
if (j == start) row.push('*');
if (j == end) row.push('*');
else row.push(j % 2 == 0 ? 1 : 0)
}
}
grid += row.join('') + '\n'
}
return grid;
}
console.log(build(3))
console.log(build(6))
console.log(build(9))

Efficiently count the number of bits in an integer in JavaScript

Let's say I have an integer I and want to get the count of 1s in its binary form.
I am currently using the following code.
Number(i.toString(2).split("").sort().join("")).toString().length;
Is there a faster way to do this? I am thinking about using bitwise operators. Any thoughts?
NOTE: i is within the 32-bit limitation.
You can use a strategy from this collection of Bit Twiddling Hacks:
function bitCount (n) {
n = n - ((n >> 1) & 0x55555555)
n = (n & 0x33333333) + ((n >> 2) & 0x33333333)
return ((n + (n >> 4) & 0xF0F0F0F) * 0x1010101) >> 24
}
console.log(bitCount(0xFF)) //=> 8
Note that the above strategy only works for 32-bit integers (a limitation of bitwise operators in JavaScript).
A more general approach for larger integers would involve counting 32-bit chunks individually (thanks to harold for the inspiration):
function bitCount (n) {
var bits = 0
while (n !== 0) {
bits += bitCount32(n | 0)
n /= 0x100000000
}
return bits
}
function bitCount32 (n) {
n = n - ((n >> 1) & 0x55555555)
n = (n & 0x33333333) + ((n >> 2) & 0x33333333)
return ((n + (n >> 4) & 0xF0F0F0F) * 0x1010101) >> 24
}
console.log(bitCount(Math.pow(2, 53) - 1)) //=> 53
You could also use a regular expression:
function bitCount (n) {
return n.toString(2).match(/1/g).length
}
console.log(bitCount(0xFF)) //=> 8
A recursive very nice but slow way:
function count1(n, accumulator=0) {
if (n === 0) {
return accumulator
}
return count1(n/2, accumulator+(n&1))
}
console.log(count1(Number.MAX_SAFE_INTEGER));
But if you want a very fast one (faster than T.J. Crowder answer)):
count1s=(n)=>n.toString(2).replace(/0/g,"").length
console.log(count1s(Number.MAX_SAFE_INTEGER));
Note: some of the other solutions do not work with bit integers (> 32 bit)
these two do!
Now, if we consider only 32 bit numbers, the fastest way is this:
function count1s32(i) {
var count = 0;
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
i = (i + (i >> 4)) & 0x0f0f0f0f;
i = i + (i >> 8);
i = i + (i >> 16);
count += i & 0x3f;
return count;
}
console.log(count1s32(0xffffffff));
https://jsperf.com/count-1/1
53 bit comparison:
32 bit comparison:
Benchmark here! (since jsperf is often down).
function log(data) {
document.getElementById("log").textContent += data + "\n";
}
benchmark = (() => {
time_function = function(ms, f, num) {
var z;
var t = new Date().getTime();
for (z = 0;
((new Date().getTime() - t) < ms); z++) f(num);
return (z / ms)
} // returns how many times the function was run in "ms" milliseconds.
// two sequential loops
count1s = (n) => n.toString(2).replace(/0/g, "").length
// three loops and a function.
count1j = (n) => n.toString(2).split('').filter(v => +v).length
/* Excluded from test because it's too slow :D
function count1(n, accumulator=0) {
if (n === 0) {
return accumulator
}
return count1(n / 2, accumulator + (n & 1))
}
*/
function countOnes(i) {
var str = i.toString(2);
var n;
var count = 0;
for (n = 0; n < str.length; ++n) {
if (str[n] === "1") {
++count;
}
}
return count;
} // two sequential loops ( one is the toString(2) )
function count1sb(num) {
i = Math.floor(num / 0x100000000);
// if (i > 0) {
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
i = (i + (i >> 4)) & 0x0f0f0f0f;
i = i + (i >> 8);
i = i + (i >> 16);
count = i & 0x3f;
i = num & 0xffffffff;
// }
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
i = (i + (i >> 4)) & 0x0f0f0f0f;
i = i + (i >> 8);
i = i + (i >> 16);
count += i & 0x3f;
return count;
}
function benchmark() {
function compare(a, b) {
if (a[1] > b[1]) {
return -1;
}
if (a[1] < b[1]) {
return 1;
}
return 0;
}
funcs = [
[count1s, 0],
[count1j, 0],
[count1sb, 0],
[countOnes, 0]
];
funcs.forEach((ff) => {
console.log("Benchmarking: " + ff[0].name);
ff[1] = time_function(2500, ff[0], Number.MAX_SAFE_INTEGER);
console.log("Score: " + ff[1]);
})
return funcs.sort(compare);
}
return benchmark;
})()
log("Starting benchmark...\n");
res = benchmark();
console.log("Winner: " + res[0][0].name + " !!!");
count = 1;
res.forEach((r) => {
log((count++) + ". " + r[0].name + " score: " + Math.floor(10000 * r[1] / res[0][1]) / 100 + ((count == 2) ? "% *winner*" : "% speed of winner.") + " (" + Math.round(r[1] * 100) / 100 + ")");
});
log("\nWinner code:\n");
log(res[0][0].toString());
<textarea cols=80 rows=30 id="log"></textarea>
The benchmark will run for 10s.
Doing n = n & (n - 1) you removing last 1 bit in the number.
According to this, you can use the following algorithm:
function getBitCount(n) {
var tmp = n;
var count = 0;
while (tmp > 0) {
tmp = tmp & (tmp - 1);
count++;
}
return count;
}
console.log(getBitCount(Math.pow(2, 10) -1));
Given that you're creating, sorting, and joining an array, if it's literally faster you want, you're probably better off doing it the boring way:
console.log(countOnes(8823475632));
function countOnes(i) {
var str = i.toString(2);
var n;
var count = 0;
for (n = 0; n < str.length; ++n) {
if (str[n] === "1") {
++count;
}
}
return count;
}
(Use str.charAt(n) instead of str[n] if you need to support obsolete browsers.)
It's not as l33t or concise, but I bet it's faster it's much faster:
...and similarly on Firefox, IE11 (IE11 to a lesser degree).
Below works fine with any number:
var i=8823475632,count=0;while (i=Math.floor(i)) i&1?count++:0,i/=2
console.log(count); //17
change the i to the value you want or wrap it as a function
if integer is within 32-bit , below works
var i=10,count=0;while (i) i&1?count++:0,i>>=1
if you want to use an absolute one liner solution you can have a look at this.
countBits = n => n.toString(2).split('0').join('').length;
1.Here n.toString(2) converts n into binary string
2.split('0') makes array out of the binary string splitting only at
0's and hence returning an array of only 1 present in binary of n
3.join('') joins all one and making a string of 1s
4.length finds length of the string actually counting number of 1's in n.
A few more "fun" 1-liners:
Recursive: count each bit recursively until there's no more bits set
let f = x => !x ? 0 : (x & 1) + f(x >>= 1);
Functional: split the base 2 string of x and return the accumulated length of bits set
g = x => x.toString(2).split('0').map(bits => bits.length).reduce((a, b) => a + b);
Keeps on checking if last bit is 1, and then removing it. If it finds last bit is one, it adds it to its result.
Math.popcount = function (n) {
let result = 0;
while (n) {
result += n % 2;
n = n >>> 1;
};
return result;
};
console.log(Math.popcount(0b1010));
For 64 bits, you can represent the number as two integers, the first is the top 32 digits, and the second is the bottom 32. To count number of ones in 64 bits, you can seperate them into 2, 32 bit integers, and add the popcount of the first and second.
You can skip Number, sort and the second toString. Use filter to only consider the 1s (a truthy value) in the array then retrieve how many got through with length.
i.toString(2).split('').filter(v => +v).length
Simple solution if you just want to count number of bit!
const integer = Number.MAX_SAFE_INTEGER;
integer.toString(2).split("").reduce((acc,val)=>parseInt(acc)+parseInt(val),0);
Regex
const bitCount = (n) => (n.toString(2).match(/1/g) || []).length;
Bitwise AND, Right Shift
function bitCount(n) {
let count = 0;
while(n) {
count += n & 1;
n >>= 1;
}
return count;
}
Brian Kernighan algorithm
function bitCount(n) {
let count = 0;
while(n) {
n &= (n-1);
count ++;
}
return count;
}
test:
bitCount(0) // 0
bitCount(1) // 1
bitCount(2) // 1
bitCount(3) // 2

Convert column index into corresponding column letter

I need to convert a Google Spreadsheet column index into its corresponding letter value, for example, given a spreadsheet:
I need to do this (this function obviously does not exist, it's an example):
getColumnLetterByIndex(4); // this should return "D"
getColumnLetterByIndex(1); // this should return "A"
getColumnLetterByIndex(6); // this should return "F"
Now, I don't recall exactly if the index starts from 0 or from 1, anyway the concept should be clear.
I didn't find anything about this on gas documentation.. am I blind? Any idea?
Thank you
I wrote these a while back for various purposes (will return the double-letter column names for column numbers > 26):
function columnToLetter(column)
{
var temp, letter = '';
while (column > 0)
{
temp = (column - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column = (column - temp - 1) / 26;
}
return letter;
}
function letterToColumn(letter)
{
var column = 0, length = letter.length;
for (var i = 0; i < length; i++)
{
column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
}
return column;
}
This works good
=REGEXEXTRACT(ADDRESS(ROW(); COLUMN()); "[A-Z]+")
even for columns beyond Z.
Simply replace COLUMN() with your column number. The value of ROW() doesn't matter.
No need to reinvent the wheel here, use the GAS range instead:
var column_index = 1; // your column to resolve
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange(1, column_index, 1, 1);
Logger.log(range.getA1Notation().match(/([A-Z]+)/)[0]); // Logs "A"
=SUBSTITUTE(ADDRESS(1,COLUMN(),4), "1", "")
This takes your cell, gets it's address as e.g. C1, and removes the "1".
How it works
COLUMN() gives the number of the column of the cell.
ADDRESS(1, ..., <format>) gives an address of a cell, in format speficied by <format> parameter. 4 means the address you know - e.g. C1.
The row doesn't matter here, so we use 1.
See ADDRESS docs
Finally, SUBSTITUTE(..., "1", "") replaces the 1 in the address C1, so you're left with the column letter.
This works on ranges A-Z
formula =char(64+column())
js String.fromCharCode(64+colno)
an google spreadsheet appscript code, based on #Gardener would be:
function columnName(index) {
var cname = String.fromCharCode(65 + ((index - 1) % 26));
if (index > 26)
cname = String.fromCharCode(64 + (index - 1) / 26) + cname;
return cname;
}
In javascript:
X = (n) => (a=Math.floor(n/26)) >= 0 ? X(a-1) + String.fromCharCode(65+(n%26)) : '';
console.assert (X(0) == 'A')
console.assert (X(25) == 'Z')
console.assert (X(26) == 'AA')
console.assert (X(51) == 'AZ')
console.assert (X(52) == 'BA')
Adding to #SauloAlessandre's answer, this will work for columns up from A-ZZ.
=if(column() >26,char(64+(column()-1)/26),) & char(65 + mod(column()-1,26))
I like the answers by #wronex and #Ondra Žižka. However, I really like the simplicity of #SauloAlessandre's answer.
So, I just added the obvious code to allow #SauloAlessandre's answer to work for wider spreadsheets.
As #Dave mentioned in his comment, it does help to have a programming background, particularly one in C where we added the hex value of 'A' to a number to get the nth letter of the alphabet as a standard pattern.
Answer updated to catch the error pointed out by #Sangbok Lee. Thank you!
I was looking for a solution in PHP. Maybe this will help someone.
<?php
$numberToLetter = function(int $number)
{
if ($number <= 0) return null;
$temp; $letter = '';
while ($number > 0) {
$temp = ($number - 1) % 26;
$letter = chr($temp + 65) . $letter;
$number = ($number - $temp - 1) / 26;
}
return $letter;
};
$letterToNumber = function(string $letters) {
$letters = strtoupper($letters);
$letters = preg_replace("/[^A-Z]/", '', $letters);
$column = 0;
$length = strlen($letters);
for ($i = 0; $i < $length; $i++) {
$column += (ord($letters[$i]) - 64) * pow(26, $length - $i - 1);
}
return $column;
};
var_dump($numberToLetter(-1));
var_dump($numberToLetter(26));
var_dump($numberToLetter(27));
var_dump($numberToLetter(30));
var_dump($letterToNumber('-1A!'));
var_dump($letterToNumber('A'));
var_dump($letterToNumber('B'));
var_dump($letterToNumber('Y'));
var_dump($letterToNumber('Z'));
var_dump($letterToNumber('AA'));
var_dump($letterToNumber('AB'));
Output:
NULL
string(1) "Z"
string(2) "AA"
string(2) "AD"
int(1)
int(1)
int(2)
int(25)
int(26)
int(27)
int(28)
Simple way through Google Sheet functions, A to Z.
=column(B2) : value is 2
=address(1, column(B2)) : value is $B$1
=mid(address(1, column(B2)),2,1) : value is B
It's a complicated way through Google Sheet functions, but it's also more than AA.
=mid(address(1, column(AB3)),2,len(address(1, column(AB3)))-3) : value is AB
I also was looking for a Python version here is mine which was tested on Python 3.6
def columnToLetter(column):
character = chr(ord('A') + column % 26)
remainder = column // 26
if column >= 26:
return columnToLetter(remainder-1) + character
else:
return character
A comment on my answer says you wanted a script function for it. All right, here we go:
function excelize(colNum) {
var order = 1, sub = 0, divTmp = colNum;
do {
divTmp -= order; sub += order; order *= 26;
divTmp = (divTmp - (divTmp % 26)) / 26;
} while(divTmp > 0);
var symbols = "0123456789abcdefghijklmnopqrstuvwxyz";
var tr = c => symbols[symbols.indexOf(c)+10];
return Number(colNum-sub).toString(26).split('').map(c=>tr(c)).join('');
}
This can handle any number JS can handle, I think.
Explanation:
Since this is not base26, we need to substract the base times order for each additional symbol ("digit"). So first we count the order of the resulting number, and at the same time count the number to substract. And then we convert it to base 26 and substract that, and then shift the symbols to A-Z instead of 0-P.
Anyway, this question is turning into a code golf :)
Java Apache POI
String columnLetter = CellReference.convertNumToColString(columnNumber);
This will cover you out as far as column AZ:
=iferror(if(match(A2,$A$1:$AZ$1,0)<27,char(64+(match(A2,$A$1:$AZ$1,0))),concatenate("A",char(38+(match(A2,$A$1:$AZ$1,0))))),"No match")
A function to convert a column index to letter combinations, recursively:
function lettersFromIndex(index, curResult, i) {
if (i == undefined) i = 11; //enough for Number.MAX_SAFE_INTEGER
if (curResult == undefined) curResult = "";
var factor = Math.floor(index / Math.pow(26, i)); //for the order of magnitude 26^i
if (factor > 0 && i > 0) {
curResult += String.fromCharCode(64 + factor);
curResult = lettersFromIndex(index - Math.pow(26, i) * factor, curResult, i - 1);
} else if (factor == 0 && i > 0) {
curResult = lettersFromIndex(index, curResult, i - 1);
} else {
curResult += String.fromCharCode(64 + index % 26);
}
return curResult;
}
function lettersFromIndex(index, curResult, i) {
if (i == undefined) i = 11; //enough for Number.MAX_SAFE_INTEGER
if (curResult == undefined) curResult = "";
var factor = Math.floor(index / Math.pow(26, i));
if (factor > 0 && i > 0) {
curResult += String.fromCharCode(64 + factor);
curResult = lettersFromIndex(index - Math.pow(26, i) * factor, curResult, i - 1);
} else if (factor == 0 && i > 0) {
curResult = lettersFromIndex(index, curResult, i - 1);
} else {
curResult += String.fromCharCode(64 + index % 26);
}
return curResult;
}
document.getElementById("result1").innerHTML = lettersFromIndex(32);
document.getElementById("result2").innerHTML = lettersFromIndex(6800);
document.getElementById("result3").innerHTML = lettersFromIndex(9007199254740991);
32 --> <span id="result1"></span><br> 6800 --> <span id="result2"></span><br> 9007199254740991 --> <span id="result3"></span>
In python, there is the gspread library
import gspread
column_letter = gspread.utils.rowcol_to_a1(1, <put your col number here>)[:-1]
If you cannot use python, I suggest looking the source code of rowcol_to_a1() in https://github.com/burnash/gspread/blob/master/gspread/utils.py
Here's a two liner which works beyond ZZ using recursion:
Python
def col_to_letter(n):
l = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
return col_to_letter((n-1)//26) + col_to_letter(n%26) if n > 26 else l[n-1]
Javascript
function colToLetter(n) {
l = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
return n > 26 ? colToLetter(Math.floor((n-1)/26)) + colToLetter(n%26) : l[n-1]
}
If you need a version directly in the sheet, here a solution:
For the colonne 4, we can use :
=Address(1,4)
I keep the row number to 1 for simplicty.
The above formula returns $D$1 which is not what you want.
By modifying the formula a little bit we can remove the dollar signs in the cell reference.
=Address(1,4,4)
Adding four as the third argument tells the formula that we are not looking for absolute cell reference.
Now the returns is : D1
So you only need to remove the 1 to get the colonne lettre if you need, for example with :
=Substitute(Address(1,4,4),"1","")
That returns D.
This is a way to convert column letters to column numbers.
=mmult(ArrayFormula(ifna(vlookup(substitute(mid(rept(" ",3-len(filter(A:A,A:A<>"")))&filter(A:A,A:A<>""),sequence(1,3),1)," ",""),{char(64+sequence(26)),sequence(26)},2,0),0)*{676,26,1}),sequence(3,1,1,0))
Screenshot of the Google Sheet
Don't use 26 radix. Like below.
const n2c = n => {
if (!n) return '';
// Column number to 26 radix. From 0 to p.
// Column number starts from 1. Subtract 1.
return [...(n-1).toString(26)]
// to ascii number
.map(c=>c.charCodeAt())
.map((c,i,arr)=> {
// last digit
if (i===arr.length-1) return c;
// 10 -> p
else if (arr.length - i > 2 && arr[i+1]===48) return c===49 ? null : c-2;
// 0 -> p
else if (c===48) return 112;
// a-1 -> 9
else if (c===97) return 57;
// Subtract 1 except last digit.
// Look at 10. This should be AA not BA.
else return c-1;
})
.filter(c=>c!==null)
// Convert with the ascii table. [0-9]->[A-J] and [a-p]->[K-Z]
.map(a=>a>96?a-22:a+17)
// to char
.map(a=>String.fromCharCode(a))
.join('');
};
const table = document.createElement('table');
table.border = 1;
table.cellPadding = 3;
for(let i=0, row; i<1380; i++) {
if (i%5===0) row = table.insertRow();
row.insertCell().textContent = i;
row.insertCell().textContent = n2c(i);
}
document.body.append(table);
td:nth-child(odd) { background: gray; color: white; }
td:nth-child(even) { background: silver; }
Simple typescript functional approach
const integerToColumn = (integer: number): string => {
const base26 = (x: number): string =>
x < 26
? String.fromCharCode(65 + x)
: base26((x / 26) - 1) + String.fromCharCode(65 + x % 26)
return base26(integer)
}
console.log(integerToColumn(0)) // "A"
console.log(integerToColumn(1)) // "B"
console.log(integerToColumn(2)) // "C"
Here is a general version written in Scala. It's for a column index start at 0 (it's simple to modify for an index start at 1):
def indexToColumnBase(n: Int, base: Int): String = {
require(n >= 0, s"Index is non-negative, n = $n")
require(2 <= base && base <= 26, s"Base in range 2...26, base = $base")
def digitFromZeroToLetter(n: BigInt): String =
('A' + n.toInt).toChar.toString
def digitFromOneToLetter(n: BigInt): String =
('A' - 1 + n.toInt).toChar.toString
def lhsConvert(n: Int): String = {
val q0: Int = n / base
val r0: Int = n % base
val q1 = if (r0 == 0) (n - base) / base else q0
val r1 = if (r0 == 0) base else r0
if (q1 == 0)
digitFromOneToLetter(r1)
else
lhsConvert(q1) + digitFromOneToLetter(r1)
}
val q: Int = n / base
val r: Int = n % base
if (q == 0)
digitFromZeroToLetter(r)
else
lhsConvert(q) + digitFromZeroToLetter(r)
}
def indexToColumnAtoZ(n: Int): String = {
val AtoZBase = 26
indexToColumnBase(n, AtoZBase)
}
In PowerShell:
function convert-IndexToColumn
{
Param
(
[Parameter(Mandatory)]
[int]$col
)
"$(if($col -gt 26){[char][int][math]::Floor(64+($col-1)/26)})$([char](65 + (($col-1) % 26)))"
}
Here is a 0-indexed JavaScript function without a maximum value, as it uses a while-loop:
function indexesToA1Notation(row, col) {
const letterCount = 'Z'.charCodeAt() - 'A'.charCodeAt() + 1;
row += 1
let colName = ''
while (col >= 0) {
let rem = col % letterCount
colName = String.fromCharCode('A'.charCodeAt() + rem)
col -= rem
col /= letterCount
}
return `${colName}${row}`
}
//Test runs:
console.log(indexesToA1Notation(0,0)) //A1
console.log(indexesToA1Notation(37,9)) //J38
console.log(indexesToA1Notation(5,747)) //ABT6
I wrote it for a web-app, so I'm not 100% sure it works in Google Apps Script, but it is normal JavaScript, so I assume it will.
For some reason I cant get the snippet to show its output, but you can copy the code to some online playground if you like
Here's a zero-indexed version (in Python):
letters = []
while column >= 0:
letters.append(string.ascii_uppercase[column % 26])
column = column // 26 - 1
return ''.join(reversed(letters))

Categories