JavaScript: Get the second digit from a number? - javascript

I have a number assigned to a variable, like that:
var myVar = 1234;
Now I want to get the second digit (2 in this case) from that number without converting it to a string first. Is that possible?

So you want to get the second digit from the decimal writing of a number.
The simplest and most logical solution is to convert it to a string :
var digit = (''+myVar)[1];
or
var digit = myVar.toString()[1];
If you don't want to do it the easy way, or if you want a more efficient solution, you can do that :
var l = Math.pow(10, Math.floor(Math.log(myVar)/Math.log(10))-1);
var b = Math.floor(myVar/l);
var digit = b-Math.floor(b/10)*10;
Demonstration
For people interested in performances, I made a jsperf. For random numbers using the log as I do is by far the fastest solution.

1st digit of number from right → number % 10 = Math.floor((number / 1) % 10)
1234 % 10; // 4
Math.floor((1234 / 1) % 10); // 4
2nd digit of number from right → Math.floor((number / 10) % 10)
Math.floor((1234 / 10) % 10); // 3
3rd digit of number from right → Math.floor((number / 100) % 10)
Math.floor((1234 / 100) % 10); // 2
nth digit of number from right → Math.floor((number / 10^n-1) % 10)
function getDigit(number, n) {
return Math.floor((number / Math.pow(10, n - 1)) % 10);
}
number of digits in a number → Math.max(Math.floor(Math.log10(Math.abs(number))), 0) + 1 Credit to: https://stackoverflow.com/a/28203456/6917157
function getDigitCount(number) {
return Math.max(Math.floor(Math.log10(Math.abs(number))), 0) + 1;
}
nth digit of number from left or right
function getDigit(number, n, fromLeft) {
const location = fromLeft ? getDigitCount(number) + 1 - n : n;
return Math.floor((number / Math.pow(10, location - 1)) % 10);
}

Get rid of the trailing digits by dividing the number with 10 till the number is less than 100, in a loop. Then perform a modulo with 10 to get the second digit.
if (x > 9) {
while (x > 99) {
x = (x / 10) | 0; // Use bitwise '|' operator to force integer result.
}
secondDigit = x % 10;
}
else {
// Handle the cases where x has only one digit.
}

A "number" is one thing.
The representation of that number (e.g. the base-10 string "1234") is another thing.
If you want a particular digit in a decimal string ... then your best bet is to get it from a string :)
Q: You're aware that there are pitfalls with integer arithmetic in Javascript, correct?
Q: Why is it so important to not use a string? Is this a homework assignment? An interview question?

You know, I get that the question asks for how to do it without a number, but the title "JavaScript: Get the second digit from a number?" means a lot of people will find this answer when looking for a way to get a specific digit, period.
I'm not bashing the original question asker, I'm sure he/she had their reasons, but from a search practicality standpoint I think it's worth adding an answer here that does convert the number to a string and back because, if nothing else, it's a much more terse and easy to understand way of going about it.
let digit = Number((n).toString().split('').slice(1,1))
// e.g.
let digit = Number((1234).toString().split('').slice(1,1)) // outputs 2
Getting the digit without the string conversion is great, but when you're trying to write clear and concise code that other people and future you can look at really quick and fully understand, I think a quick string conversion one liner is a better way of doing it.

function getNthDigit(val, n){
//Remove all digits larger than nth
var modVal = val % Math.pow(10,n);
//Remove all digits less than nth
return Math.floor(modVal / Math.pow(10,n-1));
}
// tests
[
0,
1,
123,
123456789,
0.1,
0.001
].map(v =>
console.log([
getNthDigit(v, 1),
getNthDigit(v, 2),
getNthDigit(v, 3)
]
)
);

This is how I would do with recursion
function getDigits(n, arr=[]) {
arr.push(n % 10)
if (n < 10) {
return arr.reverse()
}
return getDigits(Math.floor(n/10),arr)
}
const arr = getDigits(myVar)
console.log(arr[2])

I don’t know why you need this logic, but following logic will get you the second number
<script type="text/javascript">
var myVal = 58445456;
var var1 = new Number(myVal.toPrecision(1));
var var2 = new Number(myVal.toPrecision(2));
var rem;
rem = var1 - var2;
var multi = 0.1;
var oldvalue;
while (rem > 10) {
oldvalue = rem;
rem = rem * multi;
rem = rem.toFixed();
}
alert(10-rem);
</script>

function getDigit(number, indexFromRight) {
var maxNumber = 9
for (var i = 0; i < indexFromRight - 2; i++) {
maxNumber = maxNumber * 10 + 9
}
if (number > maxNumber) {
number = number / Math.pow(10, indexFromRight - 1) | 0
return number % 10
} else
return 0
}

Just a simple idea to get back any charter from a number as a string or int:
const myVar = 1234;
String(myVar).charAt(1)
//"2"
parseInt(String(myVar).charAt(1))
//2

you can use this function
index = 0 will give you the first digit from the right (the ones)
index = 1 will give you the second digit from the right (the tens)
and so on
const getDigit = (num, index) => {
if(index === 0) {
return num % 10;
}
let result = undefined;
for(let i = 1; i <= index; i++) {
num -= num % 10;
num /= 10;
result = num % 10;
}
return result;
}
for Example:
getDigit(125, 0) // returns 5
gitDigit(125, 1) // returns 2
gitDigit(125, 2) // returns 1
gitDigit(125, 3) // returns 0

function left(num) {
let newarr = [];
let numstring = num.split('[a-z]').join();
//return numstring;
const regex = /[0-9]/g;
const found = numstring.match(regex);
// return found;
for(i=0; i<found.length; i++){
return found[i];
}
}
//}
console.log(left("TrAdE2W1n95!"))

function getNthDigit(n, number){
return ((number % Math.pow(10,n)) - (number % Math.pow(10,n-1))) / Math.pow(10,n-1);
}
Explanation (Number: 987654321, n: 5):
a = (number % Math.pow(10,n)) - Remove digits above => 54321
b = (number % Math.pow(10,n-1)) - Extract digits below => 4321
a - b => 50000
(a - b) / 10^(5-1) = (a - b) / 10000 => 5

var newVar = myVar;
while (newVar > 100) {
newVar /= 10;
}
if (newVar > 0 && newVar < 10) {
newVar = newVar;
}
else if (newVar >= 10 && newVar < 20) {
newVar -= 10;
}
else if (newVar >= 20 && newVar < 30) {
newVar -= 20;
}
else if (newVar >= 30 && newVar < 40) {
newVar -= 30;
}
else if (newVar >= 40 && newVar < 50) {
newVar -= 40;
}
else if (newVar >= 50 && newVar < 60) {
newVar -= 50;
}
else if (newVar >= 60 && newVar < 70) {
newVar -= 60;
}
else if (newVar >= 70 && newVar < 80) {
newVar -= 70;
}
else if (newVar >= 80 && newVar < 90) {
newVar -= 80;
}
else if (newVar >= 90 && newVar < 100) {
newVar -= 90;
}
else {
newVar = 0;
}
var secondDigit = Math.floor(newVar);
That's how I'd do it :)
And here's a JSFiddle showing it works :) http://jsfiddle.net/Cuytd/
This is also assuming that your original number is always greater than 9... If it's not always greater than 9 then I guess you wouldn't be asking this question ;)

Related

Incrementing function

I am currently trying to create a function that increment numbers. The thing is that I would like the function to be able to change the incrementing value each time a "power of ten" is reached. I have a first function that handle the "incrementing value".
Here is what I have so far:
function getInc(num) {
let abs = Math.abs(num);
let inc = Math.pow(10, Math.floor(Math.log10(abs)));
if (abs === num) return inc;
if (num === -10) { return -1; }
if (num === -1) { return -0.1; }
return -inc
}
This works well, except from values likes -10, -0.1.
For : getInc(-0.1) the result should be -0.01, but my current function returns -0.1
I would like to avoid lines like if (num === -10) { return -1; } because I can not handle all the cases this way, but I am a little stuck here.
Thank you in advance.
Edit: this is the rest of the code, the function that actually increments, if this can help understand how the getInc result is used:
if ((num < -1) && (num >= -10) ) {
return Math.floor(Math.round(num) - getInc(num))
}
if ((num <= 0) && (num >= -1) ) {
return num - getInc(num)
}
if (num >= 1 && num < 10) {
return Math.round(Math.floor(num + getInc(num))) ;
}
if ((num >= 10) || (num > 0 && num < 1)) {
const result = Math.ceil(num / getInc(num)) * getInc(num);
if (result === num) { return num + getInc(num) }
else { return result }
}
if (num < -10) {
const result = Math.ceil(num / getInc(num)) * getInc(num) - getInc(num);
if (result === num) { return num + getInc(num) }
else { return result }
}
}
Desired results example:
getInc(-10) : -1
getInc(-4) : -1
getInc(-1) : -0.1
getInc(-0.4) : -0.1
getInc(-0.1) : -0.01
getInc(-0.04) : -0.01
getInc(-0.01) : -0.001
For now I have:
getInc(-10) : -10
getInc(-4) : -1
getInc(-1) : -1
getInc(-0.4) : -0.1
getInc(-0.1) : -0.1
getInc(-0.04) : -0.01
getInc(-0.01) : -0.01
You could check the sign if the log value is an integer.
function getInc(num) {
const
sign = Math.sign(num),
log = Math.log10(Math.abs(num));
return sign * Math.pow(10, Math.floor(log) - (sign === -1 && Number.isInteger(log)));
}
console.log(getInc(9)); // 1
console.log(getInc(10)); // 10
console.log(getInc(-10)); // -1 adjust - 1
console.log(getInc(-4)); // -1
console.log(getInc(-1)); // -0.1 adjust - 1
console.log(getInc(-0.4)); // -0.1
console.log(getInc(-0.1)); // -0.01 adjust - 1
console.log(getInc(-0.04)); // -0.01
console.log(getInc(-0.01)); // -0.001 adjust - 1
.as-console-wrapper { max-height: 100% !important; top: 0; }
your problem are, that numbers, that are already a power of ten are not changed by the expression Math.pow(10, Math.floor(Math.log10(abs))) (because of Math ... if num === power of 10 --> Math.log10(num) === integer (not float) ---> Math.flat() has no effect on integers --> the expression remaining is Math.pow(10, Math.log10(num)) which is the same as just num)
But you want numbers, that already are a power of ten to return a power of ten (but the exponent being one lower as the exponent of num - in easy words, you want the number to get divided by ten)
so at the start of your function you check for numbers, that already are a power of ten ... if that is the case, return the number divided by ten if it is not already a power of ten proceed as it did before.
So your code basically stays the same (you just exit the function early in case of numbers already being a power of ten (and return the number divided by ten)
here's your code with the if clause implemented:
function getInc(num) {
let abs = Math.abs(num);
if (Math.log10(abs) % 1 === 0) return num / 10;
let inc = Math.pow(10, Math.floor(Math.log10(abs)));
if (abs === num) return inc;
return -inc;
}
console.log(getInc(100));
console.log(getInc(4));
console.log(getInc(0.1));
console.log(getInc(-4));
console.log(getInc(-1));
console.log(getInc(-0.4));
console.log(getInc(-0.1));

How to output a number with a certain digit in a certain place in javascript

Thinking it would be like
for number from range x,y
if number in ones or number in hundreds
print
else
??? I don't know what command to do the if statement.
You may try using the modulus operator here:
for (i=100; i <= 200; ++i) {
if (i % 10 == 2 || Math.floor(i / 10) % 10 == 3) {
console.log(i);
}
else {
// turned this off for demo purposes
// console.log("???");
}
}
for (let i = 100; i <= 200; i++) {
if (i % 10 === 2 || (i / 10) % 10 === 3) {
// do something
} else {
console.log('???')
}
}
You could store the tensDigit and onesDigit in variables and then check them in the if statement for better readabilty:
for (let num = 100; num <= 200; num++) {
const tensDigit = Math.floor((num % 100) / 10);
const onesDigit = num % 10;
if (tensDigit === 3 || onesDigit === 2) {
console.log(num);
}
}
your question is super ambiguous, please be more specific. That being said this function should do what you are asking.
function printIfDigitIsInPlace(INPUT, DIGIT, PLACE) {
const arr = Array.from(INPUT.toString());
if (arr[PLACE] === DIGIT.toString()) console.log(INPUT);
}

Rotate Digits problem - Why taking n mod 10 and n /10?

I was trying to solve this problem on a leet code called Rotate digits.
This is the working solution of the problem in Javascript :
var IsGood = function(n){
let result = false;
while(n > 0){
let digit = n % 10; // 2 % 10
// ignore 0, 1, 8; by themselves, no change
if( (digit === 3) || (digit === 4) || (digit === 7) ) return false;
if( (digit === 2) || (digit === 5) || (digit === 6) || (digit === 9) ) result = true;
n /= 10;
}
return result;
}
var rotatedDigits = function(N) {
let count = 0;
for(let i = 1; i <= N; i++){
if(IsGood(i)) count++;
}
return count;
}
My question inside the IsGood function why are we taking n % 10 and then dividing n /=10. I have seen this implementation in almost all solutions to this problem. Can someone please explain the logic behind this?
Take the number 123
The remainder of that number when divided by 10 is 3 (123 % 10) = 3.
So n%10 is giving you the last digit of the number
If you want to test the next digit in the number you have to remove the 3. The way to do that is to divide by 10 and only take the integer part (12.3 lose the .3 part) which you get by 123 / 10
You can keep doing that until you get to a number less than 10 which must be the final digit! this algorithm is a way to examine each digit in a number using math rather than string manipulation
123 % 10 = 3 first digit
123 / 10 = 12
12 % 10 = 2 next digit
12 / 10 = 1
1 < 10 so final digit

Check if integer contains digit javascript

How do you check whether or not an integer contains a digit?
For example:
var n = 12;
var m = 34;
n contains 1 // true
m contains 1 // false
What's the fastest (performance wise) way to do this without turning the integer into a string?
Refer to the following code (if the comments aren't good enough feel free to ask):
function contains(number, digit) {
if (number < 0) { // make sure negatives are dealt with properly, alternatively replace this if statement with number = Math.abs(number)
number *= -1;
}
if (number == digit) { // this is to deal with the number=0, digit=0 edge case
return true;
}
while (number != 0) { // stop once all digits are cut off
if (number % 10 == digit) { // check if the last digit matches
return true;
}
number = Math.floor(number / 10); // cut off the last digit
}
return false;
}
Here's a simple recursive form -
const contains = (q, p) =>
p < 10
? p === q
: p % 10 === q || contains(q, p / 10 >>> 0)
console.log(contains(1, 12)) // true
console.log(contains(1, 34)) // false
console.log(contains(9, 14293)) // true
console.log(contains(9, 1212560283)) // false
if (n.toString().includes("1")) {
/// Do something
}
try this:
let n = 1234;
let flag = false;
while (n > 0){
r = n % 10;
if(r == 1){
flag = true;
break;
}
n = (n - (n % 10)) / 10;
}
console.log("n contains 1 = "+flag);

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