次のコードは、数値にマップされる名前のシーケンスを定義します。番号を取得して特定の名前を取得するように設計されています。このクラスは、名前がキャッシュに存在することを確認して動作し、キャッシュにインデックスを付けて名前を返します。この質問:キャッシュを保存せずに、番号に基づいて名前を計算するにはどうすればよいですか?
名前は、常にベース53にある最初の桁を除いて、ベース63の番号と考えることができます。
class NumberToName:
def __generate_name():
def generate_tail(length):
if length > 0:
for char in NumberToName.CHARS:
for extension in generate_tail(length - 1):
yield char + extension
else:
yield ''
for length in itertools.count():
for char in NumberToName.FIRST:
for extension in generate_tail(length):
yield char + extension
FIRST = ''.join(sorted(string.ascii_letters + '_'))
CHARS = ''.join(sorted(string.digits + FIRST))
CACHE = []
NAMES = __generate_name()
@classmethod
def convert(cls, number):
for _ in range(number - len(cls.CACHE) + 1):
cls.CACHE.append(next(cls.NAMES))
return cls.CACHE[number]
def __init__(self, *args, **kwargs):
raise NotImplementedError()
次の対話型セッションは、順番に返されると予想される値の一部を示しています。
>>> NumberToName.convert(0)
'A'
>>> NumberToName.convert(26)
'_'
>>> NumberToName.convert(52)
'z'
>>> NumberToName.convert(53)
'A0'
>>> NumberToName.convert(1692)
'_1'
>>> NumberToName.convert(23893)
'FAQ'
残念ながら、これらの番号はこれらの正確な名前にマップする必要があります(逆変換を可能にするため)。
注意:可変数のビットが受信され、明確に数値に変換されます。この番号は、Python識別子の名前空間の名前に明確に変換する必要があります。最終的に、有効なPython名は数値に変換され、これらの数値は可変ビット数に変換されます。
最終的解決:
import string
HEAD_CHAR = ''.join(sorted(string.ascii_letters + '_'))
TAIL_CHAR = ''.join(sorted(string.digits + HEAD_CHAR))
HEAD_BASE, TAIL_BASE = len(HEAD_CHAR), len(TAIL_CHAR)
def convert_number_to_name(number):
if number < HEAD_BASE: return HEAD_CHAR[number]
q, r = divmod(number - HEAD_BASE, TAIL_BASE)
return convert_number_to_name(q) + TAIL_CHAR[r]