2

I have a requirement for a custom number system in C# which goes as following:

A - 1
B - 2
...
Z - 26
AA - 27
AB - 28

I've made a function that converts from arbitrary strings to numbers like this:

    private const int Min = 'A';
    private const int Max = 'Z';
    private const int Base = Max - Min + 1;

    private static int GetCharValue(char c)
    {
        if (c < Min || c > Max)
            throw new ArgumentOutOfRangeException(nameof(c), c, $"Character needs to be between '{Min}' and '{Max}', was '{c}'.");

        return c - Min + 1;
    }

    public static int GetStringValue(string s)
    {
        char[] chars = s.ToCharArray();
        int[] values = new int[chars.Length];
        for (var i = 0; i < chars.Length; i++)
        {
            values[i] = GetCharValue(chars[i]);
        }

        int position = 1;
        int value = 0;
        for (var i = values.Length - 1; i >= 0; i--)
        {
            value += position * values[i];
            position *= Base;
        }

        return value;
    }

I've tested it to be working for up to AAA (not rigorously, just skimming over the output of printing them all). However, I can't for the life of me figure out how to write the reverse function. In other words, I need 1 to return A, 26 to return Z and 27 to return AA. The "problem" is that this number system has no 0, so it doesn't easily convert to any base. For instance, if A was 0, then AA would also be 0, but it's not. So how do I solve this?

Alxandr
  • 12,345
  • 10
  • 59
  • 95
  • 2
    ...Or `AAA` is `703`? – Dmitry Bychenko Jul 25 '17 at 12:40
  • it seems like you're trying to create a base_n number system... but i don't think `AA` should represent what you think it does – Kritner Jul 25 '17 at 12:41
  • The "problem" is that your numeric system does have a zero, but it isn't consistent. It's some weird not really positional system. In `AA`, the first `A` is one, while the second `A` is zero. Should `AAA` mean 011, 010, 100, 101, 110...? What's the actual requirement, just some vague expectation from a customer that doesn't really know what he wants? Or are you trying to replicate Excel's coordinate system? – Luaan Jul 25 '17 at 12:41
  • 1
    @DavidG: `int result = source.Aggregate(0, (s, a) => s * 26 + a - 'A' + 1);` where `source = "AAA";` – Dmitry Bychenko Jul 25 '17 at 12:41
  • @Luaan excels coordinate system is probably mostly the same. `ZZ: 702` and `AAA: 703`. We have an old system where it was just done manually (handled up to `AZ`, after which it failed). I need the old values to be valid. – Alxandr Jul 25 '17 at 12:45
  • Do you need to go to arbitrarily high values or would you be happy to just go up to ZZZ or something? If so then you could just write separate conversions for the one, two and three letter conversions which would be pretty easy. – Chris Jul 25 '17 at 12:51
  • most probably you are looking for this https://stackoverflow.com/questions/5384554/in-c-how-can-i-build-up-array-from-a-to-zz-that-is-similar-to-the-way-that-exc/5384651. you just have to replace the value of n = 0 in generate method with n = -1. – YOusaFZai Jul 25 '17 at 12:57
  • https://stackoverflow.com/questions/181596/how-to-convert-a-column-number-eg-127-into-an-excel-column-eg-aa – Chris Jul 25 '17 at 12:59
  • @DavidG Closing as duplicate is wrong - link refers to `hexavigesimal` system while author wants `bijective base-26` system – MBo Jul 25 '17 at 13:00
  • @MBo The base of a number doesn't specify the characters used to represent the digits. There are answers in the dupe that allow you to specify the range of characters used. ([example](https://stackoverflow.com/a/35004409/1663001)) – DavidG Jul 25 '17 at 13:01
  • 1
    Is this correct? https://ideone.com/vqHqBu – Lasse V. Karlsen Jul 25 '17 at 13:02
  • Would have been easier to edit the dupe target, than to reopen... – DavidG Jul 25 '17 at 13:09
  • @LasseV.Karlsen that does seem correct, yes. Thank you very much :) – Alxandr Jul 25 '17 at 13:09
  • @DavidG: I'm not sure I know how to do that... – Chris Jul 25 '17 at 13:14
  • @Chris Click the edit button next to the dupe link at the top (maybe you need a gold tag badge for that?) – DavidG Jul 25 '17 at 13:14
  • @DavidG: Yup. No edit button here. Hopefully tomorrow... ;-) – Chris Jul 25 '17 at 13:15
  • @DavidG: Yeah, apparently the job that adds up the tag numbers runs at about 03:00UTC and I think I then need to wait for a badge awarding job to run. I decided that doing too much research into this was probably a little bit much. :) Thanks if that upvote I just got was yours though - I wasn't fishing though - I promise! – Chris Jul 25 '17 at 13:19

1 Answers1

0

you can simply generate it like this....

    public static IEnumerable<string> generate()
    {
        long n = -1;
        while (true) yield return toBase26(++n);
    }

    public static string toBase26(long i)
    {
        if (i == 0) return ""; i--;
        return toBase26(i / 26) + (char)('A' + i % 26);
    }



    public static void BuildQuery()
    {
        IEnumerable<string> lstExcelCols = generate();
        try
        {

            string s = lstExcelCols.ElementAtOrDefault(1) ;
        }
        catch (Exception exc)
        {

        }


    }
YOusaFZai
  • 698
  • 5
  • 21