Related
can anyone come with an idea of how to sort an integer without using an array, and without using string methods as well as sort() method?
for example
input: 642531
output: 123456
I started by writing 2 simple functions - one which checks the length of the number, the other one splits the integer at some point and switches between 2 desired numbers. Below are the 2 functions.
I got stuck with the rest of the solution...
function switchDigits(num, i) { // for input: num=642531, i = 4 returns 624135
let temp = num;
let rest = 0;
for (let j = 0; j < i - 1; j++) {
rest = rest * 10;
rest = rest + temp % 10;
temp = (temp - temp % 10) / 10;
}
let a = temp % 10;
temp = (temp - a) / 10;
let b = temp % 10;
temp = (temp - b) / 10;
temp = Math.pow(10, i - 2) * temp;
temp = temp + 10 * a + b;
temp = Math.pow(10, i - 1) * temp;
temp = temp + rest;
return temp;
}
function checkHowManyDigits(num) { //input: 642534, output: 6 (length of the integer)
let count = 0;
while (num > 0) {
let a = num % 10;
num = (num - a) / 10;
count++;
}
return count;
}
let num = 642534;
let i = checkHowManyDigits(num);
console.log(switchDigits(num));
It actually complicated requirement and so does this answer. It's pure logic and as it is it's a question from a test you should try understanding the logic on your own as a homework.
function checkHowManyDigits(num) { //input: 642534, output: 6 (length of the integer)
let count = 0;
while (num > 0) {
let a = num % 10;
num = (num - a) / 10;
count++;
}
return count;
}
function sortDigit(numOriginal) {
let i = checkHowManyDigits(numOriginal);
let minCount = 0;
let min = 10;
let num = numOriginal;
while (num > 0) {
let d = num % 10;
num = (num - d) / 10;
if (d < min) {
min = d;
minCount = 0;
} else if (d === min) {
minCount++;
}
}
let result = 0;
while (minCount >= 0) {
result += min * Math.pow(10, i - minCount - 1);
minCount--;
}
let newNum = 0;
num = numOriginal;
while (num > 0) {
let d = num % 10;
num = (num - d) / 10;
if (d !== min) {
newNum = newNum * 10 + d;
}
}
if (newNum == 0) return result;
else return result += sortDigit(newNum);
}
console.log(sortDigit(642531));
You could have a look to greater and smaller pairs, like
64
46
The delta is 18, which gets an idea if you compare other pairs, like
71
17
where the delta is 54. Basically any difference of two digits is a multiple of 9.
This in mind, you get a function for taking a single digit out of a number and a single loop who is sorting the digits by using the calculated delta and subtract the value, adjusted by the place.
function sort(number) {
const
getDigit = e => Math.floor(number / 10 ** e) % 10,
l = Math.ceil(Math.log10(number)) - 1;
let e = l;
while (e--) {
const
left = getDigit(e + 1),
right = getDigit(e);
if (left <= right) continue;
number += (right - left) * 9 * 10 ** e;
e = l;
}
return number;
}
console.log(sort(17)); // 17
console.log(sort(71)); // 17
console.log(sort(642531)); // 123456
console.log(sort(987123654)); // 123456789
So eventually I found the best solution.
*This solution is based on a Java solution I found in StackOverFlow forums.
let store = 0;
function getReducedNumbr(number, digit) {
console.log("Remove " + digit + " from " + number);
let newNumber = 0;
let repeateFlag = false;
while (number>0) {
let t = number % 10;
if (t !== digit) {
newNumber = (newNumber * 10) + t;
} else if (t == digit) {
if (repeateFlag) {
console.log(("Repeated min digit " + t + " found. Store is : " + store));
store = (store * 10) + t;
console.log("Repeated min digit " + t + " added to store. Updated store is : " + store);
} else {
repeateFlag = true;
}
}
number = Math.floor(number / 10);
}
console.log("Reduced number is : " + newNumber);
return newNumber;}
function sortNum(num) {
let number = num;
let original = number;
let digit;
while (number > 0) {
digit = number % 10;
console.log("Last digit is : " + digit + " of number : " + number);
temp = Math.floor(number/10);
while (temp > 0) {
console.log("subchunk is " + temp);
t = temp % 10;
if (t < digit) {
digit = t;
}
temp = Math.floor(temp/10);
}
console.log("Smallest digit in " + number + " is " + digit);
store = (store * 10) + digit;
console.log("store is : " + store);
number = getReducedNumbr(number, digit);
}
console.log(("Ascending order of " + original + " is " + store));
return store;
}
console.log(sortNum(4214173));
you can see how it works here https://jsfiddle.net/9dpm14fL/1/
I have a signed value given as a hex number, by example 0xffeb and want convert it into -21 as a "normal" Javascript integer.
I have written some code so far:
function toBinary(a) { //: String
var r = '';
var binCounter = 0;
while (a > 0) {
r = a%2 + r;
a = Math.floor(a/2);
}
return r;
}
function twoscompl(a) { //: int
var l = toBinaryFill(a).length;
var msb = a >>> (l-1);
if (msb == 0) {
return a;
}
a = a-1;
var str = toBinary(a);
var nstr = '';
for (var i = 0; i < str.length; i++) {
nstr += str.charAt(i) == '1' ? '0' : '1';
}
return (-1)*parseInt(nstr);
}
The problem is, that my function returns 1 as MSB for both numbers because only at the MSB of the binary representation "string" is looked. And for this case both numbers are 1:
-21 => 0xffeb => 1111 1111 1110 1011
21 => 0x15 => 1 0101
Have you any idea to implement this more efficient and nicer?
Greetings,
mythbu
Use parseInt() to convert (which just accepts your hex string):
parseInt(a);
Then use a mask to figure out if the MSB is set:
a & 0x8000
If that returns a nonzero value, you know it is negative.
To wrap it all up:
a = "0xffeb";
a = parseInt(a, 16);
if ((a & 0x8000) > 0) {
a = a - 0x10000;
}
Note that this only works for 16-bit integers (short in C). If you have a 32-bit integer, you'll need a different mask and subtraction.
I came up with this
function hexToInt(hex) {
if (hex.length % 2 != 0) {
hex = "0" + hex;
}
var num = parseInt(hex, 16);
var maxVal = Math.pow(2, hex.length / 2 * 8);
if (num > maxVal / 2 - 1) {
num = num - maxVal
}
return num;
}
And usage:
var res = hexToInt("FF"); // -1
res = hexToInt("A"); // same as "0A", 10
res = hexToInt("FFF"); // same as "0FFF", 4095
res = hexToInt("FFFF"); // -1
So basically the hex conversion range depends on hex's length, ant this is what I was looking for. Hope it helps.
Based on #Bart Friederichs I've come with:
function HexToSignedInt(num, numSize) {
var val = {
mask: 0x8 * Math.pow(16, numSize-1), // 0x8000 if numSize = 4
sub: -0x1 * Math.pow(16, numSize) //-0x10000 if numSize = 4
}
if((parseInt(num, 16) & val.mask) > 0) { //negative
return (val.sub + parseInt(num, 16))
}else { //positive
return (parseInt(num,16))
}
}
so now you can specify the exact length (in nibbles).
var numberToConvert = "CB8";
HexToSignedInt(numberToConvert, 3);
//expected output: -840
function hexToSignedInt(hex) {
if (hex.length % 2 != 0) {
hex = "0" + hex;
}
var num = parseInt(hex, 16);
var maxVal = Math.pow(2, hex.length / 2 * 8);
if (num > maxVal / 2 - 1) {
num = num - maxVal
}
return num;
}
function hexToUnsignedInt(hex){
return parseInt(hex,16);
}
the first for signed integer and
the second for unsigned integer
As I had to turn absolute numeric values to int32 values that range from -2^24 to 2^24-1,
I came up with this solution, you just have to change your input into a number through parseInt(hex, 16), in your case, nBytes is 2.
function toSignedInt(value, nBytes) { // 0 <= value < 2^nbytes*4, nBytes >= 1,
var hexMask = '0x80' + '00'.repeat(nBytes - 1);
var intMask = parseInt(hexMask, 16);
if (value >= intMask) {
value = value - intMask * 2;
}
return value;
}
var vals = [ // expected output
'0x00', // 0
'0xFF', // 255
'0xFFFFFF', // 2^24 - 1 = 16777215
'0x7FFFFFFF', // 2^31 -1 = 2147483647
'0x80000000', // -2^31 = -2147483648
'0x80000001', // -2^31 + 1 = -2147483647
'0xFFFFFFFF', // -1
];
for (var hex of vals) {
var num = parseInt(hex, 16);
var result = toSignedInt(num, 4);
console.log(hex, num, result);
}
var sampleInput = '0xffeb';
var sampleResult = toSignedInt(parseInt(sampleInput, 16), 2);
console.log(sampleInput, sampleResult); // "0xffeb", -21
Based on the accepted answer, expand to longer number types:
function parseSignedShort(str) {
const i = parseInt(str, 16);
return i >= 0x8000 ? i - 0x10000 : i;
}
parseSignedShort("0xffeb"); // -21
function parseSignedInt(str) {
const i = parseInt(str, 16);
return i >= 0x80000000 ? i - 0x100000000 : i;
}
parseSignedInt("0xffffffeb"); // -21
// Depends on new JS feature. Only supported after ES2020
function parseSignedLong(str) {
if (!str.toLowerCase().startsWith("0x"))
str = "0x" + str;
const i = BigInt(str);
return Number(i >= 0x8000000000000000n ? i - 0x10000000000000000n : i);
}
parseSignedLong("0xffffffffffffffeb"); // -21
I was asked this question in an interview:
An integer is special if it can be expressed as a sum that's a palindrome (the same backwards as forwards). For example, 22 and 121 are both special, because 22 equals 11+11 and 121 equals 29+92.
Given an array of integers, count how many of its elements are special.
but I couldn't think of any solution. How can this be done?
In the stress and the hurry of an interview, I would have certainly found a dumb and naive solution.
pseudo code
loop that array containing the numbers
Looping from nb = 0 to (*the number to test* / 2)
convert nb to string and reverse the order of that string (ie : if you get "29", transform it to "92")
convert back the string to a nb2
if (nb + nb2 == *the number to test*)
this number is special. Store it in the result array
end loop
end loop
print the result array
function IsNumberSpecial(input)
{
for (let nb1 = 0; nb1 <= (input / 2); ++nb1)
{
let nb2 = parseInt(("" + nb1).split("").reverse().join("")); // get the reverse number
if (nb2 + nb1 == input)
{
console.log(nb1 + " + " + nb2 + " = " + input);
return (true);
}
}
return (false);
}
let arr = [22, 121, 42];
let len = arr.length;
let result = 0;
for (let i = 0; i < len; ++i)
{
if (IsNumberSpecial(arr[i]))
++result;
}
console.log(result + " number" + ((result > 1) ? "s" : "") + " found");
Here's a rather naïve solution in pseudocode for determining if a number is 'special':
Given an number N (assumed to be an integer)
Let I = Floor(N / 2)
Let J = Ceil(N / 2)
While (I > 0)
If I is the reverse of J Then
Return True
End
I <- I - 1
J <- J + 1
End
Return False
A quick JS implementation:
function isSpecial(n) {
for (var i = Math.floor(n / 2), j = Math.ceil(n / 2); i > 0; i--, j++) {
console.info(`checking ${i} + ${j}`);
if (i.toString().split('').reverse().join('') === j.toString())
return true;
}
return false;
}
console.log(isSpecial(121));
I'll leave it up to the you implement the function to count the special numbers in the array. This could be made more efficient by improving the rather crude method for checking for string reversals or possibly by more intelligently skipping numbers.
Some pseudo code?
num_special = 0
for item in array:
for num in range(1, total):
if num + int(string(num).reversed()) == item
num_special += 1
break
print(num_special)
EDIT:
Here's a working Python example:
array = [22, 121]
num_special = 0
for item in array:
for num in range(1, item):
if (num + int(str(num)[::-1]) == item):
num_special += 1
break
print(num_special)
https://repl.it/repls/UsedLovelyCategory
Assuming we want two summands - this does not seem to be specified in the question but every answer has assumed it!
(Without this assumption, every number can be written as a reversible sum of 1s.)
Single digit summands:
n is even
Two digit summands:
10x + y + 10y + x
11x + 11y
11(x + y)
n is divisible by 11
Three digit summands:
100x + 10y + z + 100z + 10y + x
101x + 20y + 101z
101(x + z) + 20y
more complex but we can still
do better than a brute force
loop of 1 to n / 2
Etc... (we could probably write a function that generalises and searches over this algebra)
UPDATE
JavaScript code (interestingly, a result for 1111111110 seems to be found faster by the brute force 1 to n/2 loop! Maybe some other optimisations can be made):
function f(n){
let start = new Date;
let numDigits = 0;
let t = Math.ceil(n / 2);
while (t){
numDigits++;
t = ~~(t/10);
}
// Summands split between x and x+1 digits
if (n / 2 + 0.5 == Math.pow(10, numDigits - 1))
return false;
let cs = [];
let l = Math.pow(10, numDigits - 1);
let r = 1;
while (l >= r){
cs.push(l + r);
l /= 10;
r *= 10;
}
let sxs = new Array(cs.length);
const m = cs.length & 1 || 2;
sxs[cs.length-1] = m*cs[cs.length-1];
for (let i=cs.length-2; i>=0; i--)
sxs[i] = 2*cs[i] + sxs[i + 1];
let stack = [[0, n, []]];
let results = [];
while (stack.length){
let [i, curr, vs] = stack.pop();
if (i == cs.length - 1){
let d = curr / cs[i];
if (d == ~~d &&
((cs.length & 1 && d < 10) || ((!(cs.length & 1) || cs.length == 1) && d < 19)))
results.push(vs.concat('x'));
continue;
}
t = 2;
curr -= t*cs[i];
stack.push([
i + 1, curr,
vs.slice().concat(t)]);
while (curr >= sxs[i + 1]){
curr -= cs[i];
stack.push([
i + 1, curr,
vs.slice().concat(++t)]);
}
}
let time = new Date - start;
return [!!results.length, (time) + 'ms', cs, results];
}
let ns = [
22, 121, 42,
66666,
777777,
8888888,
99999999,
68685,
68686]
for (let n of ns)
console.log(n, JSON.stringify(f(n)));
My JS variant:
const reverseInt = (n) =>
parseInt(n.toString().split('').reverse().join(''))
const checkSpecialInt = (n) =>{
for(let i=1;i<=n;i++){
if (i+reverseInt(i)==n) return true;
}
return false;
}
const checkSpecialIntArray = (arr) =>
arr.filter((e,i)=>checkSpecialInt(e)).length;
let test = [122, 121, 22, 21];
console.log(checkSpecialIntArray(test));
The requirement does not includes returning every possible combination of matched "special numbers", only that a match is found.
const isSpecialInteger = arr => {
// `arr`: `Array`
// result, initialized to `0`
let res = 0;
// iterate input `arr`
for (let n of arr) {
// divide `n` by `2`
const c = n / 2;
// check if `n` is an integer or decimal
// if decimal subtract decimal portion of 1st divided decimal
// add decimal portion to 2nd portion of divided decimal
// else set `x`, `y` to even division of input `n`
let [x, y] = !Number.isInteger(c) ? [c - (c % 10), c + (c % 10)] : [c, c];
// set label for `for` loop
// decrement result of `Math.max(x, y)`
N: for (let i = Math.max(x, y); i; i--) {
// check if `i` converted to
// string, then array reveresed
// if equal to `n`
// if `true` increment `res` by `1` `break` `N` loop
if (i + +[...`${i}`].reverse().join`` === n) {
res+= 1;
break N;
}
}
}
// return positive integer or `0`
return res;
}
console.log(
isSpecialInteger([22, 121])
);
Here is one of the brute-force approaches in JAVA and this can be optimised further,
import java.util.Scanner;
public class Solution
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
String str = in.nextLine();
String[] inp = str.split(",");
System.out.println(isSpecial(inp,inp.length));
}
public static int isSpecial(String[] inp, int inpSize)
{
int arr[] = new int[inp.length];
for(int i=0;i<inpSize;i++)
{
arr[i] = Integer.parseInt(inp[i]);
}
int spclCount = 0;
for(int i=0;i<arr.length;i++)
{
for(int j=1;j<((arr[i]/2)+1);j++)
{
if(j+getReverse(j) == arr[i])
{
spclCount++;
break;
}
}
}
return spclCount;
}
public static int getReverse(int n)
{
int rem,rev=0;
while(n != 0)
{
rem = n % 10;
rev = (rev*10) + rem;
n /= 10;
}
return rev;
}
}
Question:
An integer is special if it can be expressed as a sum that's a palindrome (the same backwards as forwards). For example, 22 and 121 are both special, because 22 equals 11+11 and 121 equals 29+92.
Given an array of integers, count how many of its elements are special
My Approach:
public class PalindromicSum {
public static void getSplNumber(int[] arrip) {
//to iterate i/p array
for (int i = 0; i < arrip.length; i++) {
int tempSum = 0;
//to iterate from 1 to number/2
for (int j = 1; j <= arrip[i] / 2; j++) {
//to get the reverse of the number
int revNum = getRevNum(j);
tempSum = revNum + j;
if (tempSum == arrip[i]) {
System.out.println(arrip[i]);
break;
}
}
}
}
public static int getRevNum(int num) {
int rev = 0;
//to get reverse of a number
while(num!=0) {
int reminder = num%10;
rev = rev*10 + reminder;
num = num/10;
}
return rev;
}
public static void main(String[] args) {
int[] arr = { 121, 11, 10, 3, 120, 110};
getSplNumber(arr);
}
}
I have a java-script function that carries out a calculation. I would like to use the answer to that calculation in my php code.
document.write(Fixed((PoissonTerm( X, Y )),8,4))
Both values X and Y come from variables within my php code so
<?php
$valueofx;
$valueofy;
?>
In the ideal world I would like to to look like this
<?php
$thejavascriptvalue = document.write(Fixed((PoissonTerm( $valueofx, $valueofy )),8,4))
?>
I know this can't be done and i have 5 different values i need to pull and use. Is there anyway I can work around it? I dont mind refreshing the page or grabbing it from another page as long as i can have 5 values to use in my php code.
I would need to run the javascript 10 times before redirecting like
document.write(Fixed((PoissonTerm(0.1, 0 )),8,4))
document.write(Fixed((PoissonTerm( 8, 2 )),8,4))
document.write(Fixed((PoissonTerm( 6, 3 )),8,4))
below if the javascript
function Fixed( s, wid, dec ) {
// many combinations of possibilities
// maybe prepare for upcoming truncate
var z = 1
if (dec > 0) {
z /= Math.pow( 10, dec );
if (s < -z) s -= 0.5 * z;
else
if (s > z) s += 0.5 * z;
else
s = 0;
}
// assure a string
s = "" + s;
// chop neg, if any
var neg = 0;
if (s.charAt(0) == "-") {
neg = 2;
s = s.substring( 1, s.length );
}
// chop exponent, if any
var exp = "";
var e = s.lastIndexOf( "E" );
if (e < 0) e = s.lastIndexOf( "e" );
if (e > -1) {
exp = s.substring( e, s.length );
s = s.substring( 0, e );
}
// if dec > 0 assure "."; dp == index of "."
var dp = s.indexOf( ".", 0 );
if (dp == -1) {
dp = s.length;
if (dec > 0) {
s += ".";
dp = s.length - 1;
}
}
// assure leading digit
if (dp == 0) {
s = '0' + s;
dp = 1;
}
// not enough dec pl? add 0's
while ((dec > 0) && ((s.length - dp - 1) < dec))
s += "0";
// too many dec pl? take a substring
var places = s.length - dp - 1;
if (places > dec)
if (dec == 0)
s = s.substring( 0, dp );
else
s = s.substring( 0, dp + dec + 1 );
// recover exponent, if any
s += exp;
// recover neg, if any
if (neg > 0)
s = "-" + s;
// if not enough width, add spaces IN FRONT
// too many places? tough!
while (s.length < wid)
s = " " + s;
return s
}
function Prb( x ) {
if (x < 0) x = 0;
else
if (x > 1) x = 1;
return x;
}
function PosV( x ) {
if (x < 0) x = -x;
return x;
}
// FACTORIALS
function Fact( x ) {
// x factorial
var t=1;
while (x > 1)
t *= x--;
return t;
}
function LnFact( x ) {
// ln(x!) by Stirling's formula
// see Knuth I: 111
if (x <= 1) x = 1;
if (x < 12)
return Math.log( Fact(Math.round(x)) );
else {
var invx = 1 / x;
var invx2 = invx * invx;
var invx3 = invx2 * invx;
var invx5 = invx3 * invx2;
var invx7 = invx5 * invx2;
var sum = ((x + 0.5) * Math.log(x)) - x;
sum += Math.log(2*Math.PI) / 2;
sum += (invx / 12) - (invx3 / 360);
sum += (invx5 / 1260) - (invx7 / 1680);
return sum;
}
}
// POISSON
function PoissonPD( u, k ) {
// Peizer & Pratt 1968, JASA 63: 1416-1456
var s = k + (1/2);
var d1 = k + (2/3) - u;
var d2 = d1 + 0.02/(k+1);
var z = (1 + g(s/u)) / u;
z = d2 * Math.sqrt(z);
z = NormalP( z );
return z;
}
function PoissonTerm( u, k ) {
// by logs
return Math.exp( (k * Math.log(u)) - u - LnFact(k) );
}
function PoissonP( u, k ) {
// term-by-term summation
if (k >= 20) return PoissonPD( u, k );
else {
var sum = 0.0, j = 0;
while (j <= k)
sum += PoissonTerm( u, j++ );
if (sum > 1) sum = 1;
return sum;
}
}
function DoPoi( aform ) {
var u = PosV(parseFloat(aform.u.value));
aform.u.value = Fixed(u,10,4);
var k = PosV(parseInt(aform.k.value));
aform.k.value = Fixed(k,8,0);
aform.tnk.value = Fixed(PoissonTerm( u, k ),8,4);
var t = PoissonP( u, k );
aform.puk.value = Fixed(t,8,4);
aform.quk.value = Fixed(1-t,8,4);
}
This is very generic. You're going to have to modify this to your needs. But this will give you the basic idea:
<form name="thisform" action="phpPage.php" method="POST">
X: <input type="text" name="val_x" id="val_x" value="40" /><br />
Y: <input type="text" name="val_y" id="val_y" value="60" /><br />
<input type="button" onclick="sendForm();" value="send form"/>
</form>
JavaScript:
function sendForm(){
//Choose one of these methods:
//This will generate a string that you can use as a location.
//use $_GET in PHP to retrieve the values
var valofX = document.getElementById("val_x").value;
var valofy = document.getElementById("val_y").value;
generateURL = 'phpPage.php?val_x=' + valofX;
generateURL += '&val_y=' + valofy;
document.location = generateURL;
//This will submit the form.
//use $_POST in PHP to retrieve the values
document.getElementById("thisform").submit();
}
Once the form is submitted, or the location is sent, you'll need to grab the values in PHP:
$val_x = $_POST['val_x'];
$val_y = $_POST['val_y'];
//OR
$val_x = $_GET['val_x'];
$val_y = $_GET['val_y'];
You would use $_GET or $_POST depending on how the values are sent.
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))