1

I'm working on a system to replace numbers with letters for listings. I use 12 letters, such as ABCEHKMOPTXY. So such a replacement needs to use duodecimal number format.

Here is the table for convertion results, that are needed:

1 – A
2 - B
3 - C
...
11 - X
12 - Y
13 - AA
14 - AB
...
48 - CY
49 - EA
...
156 - YY
157 - AAA
158 - AAB

I try to use the .toString(12) to convert the number to a doudecimal and then replace each character in result with letters using switch - case, but there are difficulties with round doudecimal numbers, such as results for 1884.

1883 - YYX
1884 - AYY **- WRONG! Has to be YYY**
1885 - AAAA

Here is my function, that works good for numbers till 1884, but I need more universal one. Please, help!

function numToString (num) {
    var duodecimal = (+num).toString(12);
    var numArray=duodecimal.split('');
    var lttrs='';
    for (var i=0; i<numArray.length; i++) {

        switch (numArray[i]) {
             case '1':
                 lttrs+='A'
                break
            case '2':
                lttrs+='B'
                break
            case '3':
                lttrs+='C'
                break
            case '4':
                lttrs+='E'
                break
            case '5':
                lttrs+='H'
                break
            case '6':
                lttrs+='K'
                break
            case '7':
                lttrs+='M'
                break
            case '8':
                lttrs+='O'
                break
            case '9':
                lttrs+='P'
                break
            case 'a':
                lttrs+='T'
                break
            case 'b':
                lttrs+='X'
                break
            case '0':
                lttrs=lttrs.slice(0,-1);
                switch (numArray[i-1]) {
                    case '1':
                        if (numArray[i-2]) {lttrs=lttrs.slice(0,-1); lttrs+='Y'}
                        break
                    case '2':
                        lttrs+='A'
                        break
                    case '3':
                        lttrs+='B'
                        break
                    case '4':
                        lttrs+='C'
                        break
                    case '5':
                        lttrs+='E'
                        break
                    case '6':
                        lttrs+='H'
                        break
                    case '7':
                        lttrs+='K'
                        break
                    case '8':
                        lttrs+='M'
                        break
                    case '9':
                        lttrs+='O'
                        break
                    case 'a':
                        lttrs+='P'
                        break
                    case 'b':
                        lttrs+='T'
                        break
                    case '0':
                        lttrs=lttrs.slice(0,-1);

                        lttrs+='X'
                        break
                }
                lttrs+='Y'
                break
         }
    }
    return lttrs;
}
Kara
  • 6,115
  • 16
  • 50
  • 57
  • Why didn't you assign a letter to 0? – Re Captcha Apr 22 '14 at 08:04
  • Because it results in not proper letters, for example if just 0 => Y: 1 - A, 2 - B, ..., 10 - X, 11 - Y, 12 - AY (just because the doudecimal number is '10' in this case) but it must be just 'Y', 13 - AA, 14 - AB, ... – Denis Starov Apr 22 '14 at 09:10
  • Your letter assignments are quite odd for a duodecimal system. Your assignment should start at 0 and end at 11. Number 12 will be expressed as "symbol for 1"+"symbol for 0". – R. Schifini Apr 22 '14 at 17:01

2 Answers2

1

I think I got it:

function n2s(n, digits) {
    var s = '';
    var l = digits.length;
    while (n > 0) {
        s = digits.charAt((n - 1) % l) + s;
        n = Math.ceil(n / l) - 1;
    }
    return s;
}

A check in Chrome's console:

var i, letters = 'ABCEHKMOPTXY';
for (i = 1; i <= 25; i++) console.log(i, n2s(i, letters));
console.log(1884, n2s(1884, letters)); // 1884 "YYY"
console.log(1885, n2s(1885, letters)); // 1885 "AAAA"

Related stuffs: https://stackoverflow.com/a/30687539/1636522.

I'm a bit late though :-|


Reverse function

I have to admit that there is still a bit of magic for me as well, then I'm not sure to be able to give you a full explaination of what's happenning here :-D Anyway, as you requested, here is the reverse function:

function s2n(s, digits) {
    var pow, n = 0, i = 0;
    while (i++ < s.length) {
        pow = Math.pow(digits.length, s.length - i);
        n += (digits.indexOf(s.charAt(i - 1)) + 1) * pow;
    }
    return n;
}

Here is a use case by the way:

var letters = 'ABCEHKMOPTXY';
var from = s2n('YYT', letters);
var to = s2n('AAAC', letters);
for (var n = from; n <= to; n++) {
    console.log(n, n2s(n, letters));
}

Under Chrome or Firefox:

  1. Press F12.
  2. Copy-paste both functions and the code above.
  3. Press ENTER.

You should see the following lines:

1882 "YYT"
1883 "YYX"
1884 "YYY"
1885 "AAAA"
1886 "AAAB"
1887 "AAAC"
Community
  • 1
  • 1
  • 1
    Maybe it's the time! Thank you very much! That snippet helped me warm a little bit frozen project. Math is like magic! – Denis Starov Jun 08 '15 at 12:56
  • Maybe you can help to reconfigurate the s2n(n) function from that example for my case? I don't quite understand the principle. – Denis Starov Jun 08 '15 at 13:24
  • @DenisStarov I got it faster than I thought :-D I updated the answer :-) –  Jun 08 '15 at 13:35
  • @DenisStarov I could try to provide some clarifications about the math if you want, it's mainly a matter of base conversion. Considering this set of characters "ABCEHKMOPTXY", `n2s` converts from 10 to 12 while `s2n` converts from 12 to 10. However, I used a little intuition to make it work for your specific request :-| –  Jun 08 '15 at 13:56
  • Thank you twice! The functions are perfect for my use case! They're fast and simple. I'll use them in my letter numeration project and will try to understand the math behind. – Denis Starov Jun 08 '15 at 15:28
0

Here you go:

var a = 1885;  //number to convert
var v = []; //string array where duodecimal conversion is stored

var r = a%12; //obtain the remainder by division by 12

a -= r;
r = letter(r);  //obtain the corresponding letter for each decimal symbol
v = r+v;
a = a/12;

while (a>0){
  r = a%12;
  a -= r;
  r = letter(r);
  v = r+v;
  a = a/12;
}
console.log(v); // show solution in the console


function letter(r){
switch (r){
case 0:
    r = "y";
    break;
case 1:
    r = "a";
    break;
case 2:
    r = "b";
    break;
case 3:
    r = "c";
    break;
case 4:
    r = "d";
    break;
case 5:
    r = "e";
    break;
case 6:
    r = "f";
    break;
case 7:
    r = "g";
    break;
case 8:
    r = "h";
    break;
case 9:
    r = "i";
    break;
case 10:
    r = "j";
    break;
case 11:
    r = "k";
    break;
}
return r;
}
R. Schifini
  • 9,085
  • 2
  • 26
  • 32
  • Thanks! But now i realize, that my way of encoding numbers is not a true doudecimal scale, just because I need slightly more complex order. In your code the number 12 converts to AY (in my letters), but has to be just Y, for example. And also the mathematics are rather different from just converting scale. Two character numbers in true doudecimal will end on 144-th number, but in my case it ends on 156-th "number" YY. Seems I'll need to generate the full list of letters corresponding to numbers to covert it right... – Denis Starov Apr 24 '14 at 07:04
  • 1
    Any system (binary, decimal, duodecimal, etc) have a symbol for each number starting from zero (0 in binary,0 in dec, 0 in duodec or Y in yours). "Y" should not be the equivalent of 12! In fact, 12 in duodecimal should be expressed as two symbols: the first corresponding to one and the second to zero (if your symbols are: 0123456789ab => twelve = 10, if the symbols are: qwertyuiopas => twelve = wq). – R. Schifini Apr 24 '14 at 19:54
  • 144 = 1*(12^2) + 0*(12^1) + 0*(12^0). So decimal 144 is "1"+"0"+"0" (100) in duodecimal if the symbols from zero to eleven are: 0123456789AB. If the symbols are: ABCEHKMOPTXY (where A=0 and Y=11) decimal 144 is BAA ("B"="1" and "A"="0") – R. Schifini Apr 24 '14 at 19:59
  • If you still don't trust me use this converter: http://www.convertworld.com/en/numerals/Duodecimal.html – R. Schifini Apr 24 '14 at 20:02
  • 1
    If you are trying to create a 13-based system you still need a symbol for number 0. – R. Schifini Apr 24 '14 at 20:04
  • I believe you and mathematics. All you say is right for doudecimal and any other scale. I just realize, that I'm trying to create a slightly more complex system of enumeration. I can create a table of corresponding numbers and letters to show the system rules. – Denis Starov Apr 28 '14 at 09:24