Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an infinite iterator to generate an incrementing alphabet pattern?

I've created a function that generates a list of alphabets incrementing continuously. A, B, C ..., Z. After Z, it goes to AA, AB, AC ...AZ. This pattern repeats. This is similar to MS Excel's column names. At the moment, this function generates a finite list of alphabets.

_column_name_generator() = ['A', 'B', ..., 'AA', 'AB', ..., 'BA', 'BB', ..., 'CV']

I can then iterate over it in conjunction with some finite list, e.g. 0-10. See my code below. What I'd like is to create a generator that will give me an infinitely long list of incrementing alphabets.

import string


def _column_name_generator():
    column_names = []
    for x in range(0, 100):
        if x < 26:
            column_names.append(string.ascii_uppercase[x % 26])
        else:
            column_names.append(column_names[x/26 - 1] + string.ascii_uppercase[x % 26])
    return column_names

container = []
for column_name, num in zip(_column_name_generator(), range(0, 10)):
    container.append(column_name + str(num))

print _column_name_generator()
print container

container = ['A0', 'B1', 'C2', 'D3', 'E4', 'F5', 'G6', 'H7', 'I8', 'J9']
like image 741
bluprince13 Avatar asked Feb 07 '17 20:02

bluprince13


People also ask

Which function is an example of an infinite iterator?

Iterator in Python is any python type that can be used with a ' for in loop '. Python lists, tuples, dictionaries, and sets are all examples of inbuilt iterators. But it is not necessary that an iterator object has to exhaust, sometimes it can be infinite.

How do you iterate through A to Z in Python?

We will use the built-in Python function chr() to print the small alphabets from a to z. We know that the Ascii code of 'a' is 97 and that of 'z' is 122. Therefore we will use a range() function in a for loop with arguments 97, 123. This for loop will print a to z alphabets.


2 Answers

Yield column_names's last element every time, and use itertools.count instead of range to provide infinite increase:

import itertools

def _column_name_generator():
    column_names = []
    for x in itertools.count():
        if x < 26:
            column_names.append(string.ascii_uppercase[x % 26])
        else:
            column_names.append(column_names[x/26 - 1] + string.ascii_uppercase[x % 26])
        yield column_names[-1]

A better solution, altering the original code but dismissing the need in a memory consuming list of column_names, would be

import itertools, string

def _column_name_generator():
    for i in itertools.count(1):
        for p in itertools.product(string.ascii_uppercase, repeat=i):
            yield ''.join(p)

it basically iterates over the product of length i the uppercase ascii letters (every sequence possible) when i is gradually increasing, starting from 1 (A, B, C).

like image 99
Uriel Avatar answered Oct 19 '22 16:10

Uriel


A less pythonic way

As implied in your question, one way is dividing by 26 converting the remainder into a letter at every step, until the division return 0. Use % (modulo) to get the remainder, // (floor division) to update the value for the next step. This could be the code:

numberOfElements = 100
letters = []
for counter in range(numberOfElements):
    i = counter
    newCharacter = i % 26
    i //= 26
    s = "" +chr(newCharacter + ord('A') )
    while i != 0:
        newCharacter = i % 26
        i //= 26
        s = chr(newCharacter + ord('A') ) + s
    letters.append(s)
print letters

Result:

['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'BA', 'BB', 'BC', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BK', 'BL', 'BM', 'BN', 'BO', 'BP', 'BQ', 'BR', 'BS', 'BT', 'BU', 'BV', 'BW', 'BX', 'BY', 'BZ', 'CA', 'CB', 'CC', 'CD', 'CE', 'CF', 'CG', 'CH', 'CI', 'CJ', 'CK', 'CL', 'CM', 'CN', 'CO', 'CP', 'CQ', 'CR', 'CS', 'CT', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DA', 'DB', 'DC', 'DD', 'DE', 'DF', 'DG', 'DH', 'DI', 'DJ', 'DK', 'DL', 'DM', 'DN', 'DO', 'DP', 'DQ', 'DR', 'DS', 'DT', 'DU', 'DV']

like image 33
Antonio Avatar answered Oct 19 '22 15:10

Antonio