sequential counting using letters instead of numbers

Question:

I need a method that ‘increments’ the string a to z and than aa to az and then ba to bz and so on, like the columns in an excel sheet. I will feed the method the previous string and it should increment to the next letter.

PSEUDO CODE

def get_next_letter(last_letter):
    return last_letter += 1  

So I could use it like so:

>>> get_next_letter('a')
'b'
>>> get_next_letter('b')
'c'
>>> get_next_letter('c')
'd'
...
>>> get_next_letter('z')
'aa'
>>> get_next_letter('aa')
'ab'
>>> get_next_letter('ab')
'ac'
...
>>> get_next_letter('az')
'ba'
>>> get_next_letter('ba')
'bb'
...
>>> get_next_letter('zz')
'aaa'
    
Asked By: hewi

||

Answers:

Why not use openpyxl‘s get_column_letter and column_index_from_string

from openpyxl.utils import get_column_letter, column_index_from_string
# or `from openpyxl.utils.cell import get_column_letter, column_index_from_string`

def get_next_letter(s: str) -> str: 
    return get_column_letter(
        column_index_from_string(s) + 1
    ).lower()

and then

>>> get_next_letter('aab')
'aac'
>>> get_next_letter('zz')
'aaa'

?


Keeping in mind that this solution only works in [A, ZZZ[.

Answered By: keepAlive

I believe there are better ways to handle this, but you can implement the algorithm for adding two numbers on paper…

def get_next_letter(string):
    x = list(map(ord, string)) # convert to list of numbers
    x[-1] += 1 # increment last element
    result = '' 
    carry = 0;
    for c in reversed(x):
        result = chr((c + carry )) + result # i'm not accounting for when 'z' overflows here
        carry = c > ord('z')
    if carry: # add the new letter at the beggining in case there is still carry
        result = 'a' + result
    return result.replace('{', 'a') # replace overflowed 'z' with 'a'

Answered By: Fabio Almeida

I fact what you want to achieve is increment a number expressed in base26 (using the 26 alphabet letters as symbols).

We all know decimal base that we use daily.
We know hexadecimal that is in fact base16 with symbols including digits and a, b, c, d, e, f.
Example : 0xff equals 15.

An approach is to convert into base10, increment the result decimal number, then convert it back to base26.
Let me explain.

I define 2 functions.

A first function to convert a string (base26) into a base10 (decimal) number.
str_tobase10("abcd") # 19010

The inverse function to convert a base10 number (decimal) to a string (base26).
base10_tostr(19010) # abcd

get_next_letter() just has to convert the string to a number, increment by one and converts back to a string.

Advantages :

  • pure Python, no extra lib/dependency required.
  • works with very long strings

Example :
get_next_letter("abcdefghijz") # abcdefghika

def str_tobase10(value: str) -> int:
    n = 0
    for letter in value:
        n *= 26
        n += ord(letter)-ord("a")+1
    return n

def base10_tostr(value: int) -> str:
    s = ""
    n = value
    while n > 26:
        r = n % 26
        s = chr(ord("a")-1+r) + s
        n = n // 26   
    return chr(ord("a")-1+n) + s

def get_next_letter(value: str):
    n = str_tobase10(value)
    return base10_tostr(n+1)
Answered By: 0x0fba

all proposed are just way too complicated
I came up with below, using a recursive call,
this is it!

def getNextLetter(previous_letter):
    """ 
        'increments' the provide string to the next letter recursively
        raises TypeError if previous_letter is not a string 
        returns "a" if provided previous_letter was emtpy string
    """
    if not isinstance(previous_letter, str):
        raise TypeError("the previous letter should be a letter, doh")
    if previous_letter == '':
        return "a"
    for letter_location in range(len(previous_letter) - 1, -1, -1):
        if previous_letter[letter_location] == "z":
            return getNextLetter(previous_letter[:-1])+"a"
        else:
            characters = "abcdefghijklmnopqrstuvwxyz"
            return (previous_letter[:-1])
                   +characters[characters.find(previous_letter[letter_location])+1]

# EOF
Answered By: hewi
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.