2012-06-15 15 views
8

निम्न कोड संख्याओं के मैप किए गए नामों के अनुक्रम को परिभाषित करता है। यह एक संख्या लेने और एक विशिष्ट नाम पुनर्प्राप्त करने के लिए डिज़ाइन किया गया है। कक्षा अपने कैश में नाम मौजूद होने के द्वारा संचालित होती है, और उसके बाद नाम को कैश में अनुक्रमणित करके लौटाती है। इसमें सवाल: कैश को संग्रहीत किए बिना संख्या के आधार पर नाम की गणना कैसे की जा सकती है?क्या कोई संख्या किसी नाम पर बदलने का एक तेज़ तरीका है?

नाम, एक बेस 63 संख्या के रूप में सोचा जा सकता है पहले अंक के अलावा जो आधार में हमेशा होता है 53.

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' 

दुर्भाग्यवश, इन नंबरों को इन सटीक नामों (एक रिवर्स रूपांतरण की अनुमति देने के लिए) मैप करने की आवश्यकता है।


कृपया ध्यान दें: बिट्स की एक चर संख्या प्राप्त की और एक संख्या में स्पष्ट रूप से बदल रहे हैं। यह संख्या पाइथन पहचानकर्ता नामस्थान में किसी नाम पर असंबद्ध रूप से परिवर्तित की जानी चाहिए। आखिरकार, वैध पायथन नाम संख्याओं में परिवर्तित हो जाएंगे, और इन नंबरों को बिट्स की एक चर संख्या में परिवर्तित कर दिया जाएगा।


अंतिम समाधान:

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] 
+0

क्यों इस विशेष आवश्यकता? क्या आप कृपया कैश के उद्देश्य को विस्तारित कर सकते हैं? –

+0

कैश बहुत सारी मेमोरी का उपभोग करता है जिसकी वास्तव में आवश्यकता नहीं होनी चाहिए। – recursive

+2

बिट्स की एक चर संख्या प्राप्त की जाती है और असंबद्ध रूप से एक संख्या में परिवर्तित हो जाती है। यह संख्या पाइथन पहचानकर्ता नामस्थान में किसी नाम पर असंबद्ध रूप से परिवर्तित की जानी चाहिए। आखिरकार, वैध पायथन नाम संख्याओं में परिवर्तित हो जाएंगे, और इन नंबरों को बिट्स की एक चर संख्या में परिवर्तित कर दिया जाएगा। –

उत्तर

7

यह एक मजेदार थोड़ा 1 त्रुटियों से बंद का पूरा समस्या है।

छोरों के बिना:

import string 

first_digits = sorted(string.ascii_letters + '_') 
rest_digits = sorted(string.digits + string.ascii_letters + '_') 

def convert(number): 
    if number < len(first_digits): 
     return first_digits[number] 

    current_base = len(rest_digits) 
    remain = number - len(first_digits) 
    return convert(remain/current_base) + rest_digits[remain % current_base] 

और परीक्षण:

print convert(0) 
print convert(26) 
print convert(52) 
print convert(53) 
print convert(1692) 
print convert(23893) 

आउटपुट:

A 
_ 
z 
A0 
_1 
FAQ 
+0

आपकी सहायता के लिए धन्यवाद! अपने 'रहो' चर को देखकर बहुत मदद मिली। –

+1

पिछली तीन पंक्तियों के लिए वैकल्पिक:' संख्या, रहें = divmod (संख्या - लेन (first_digits), लेन (rest_digits)); वापसी कनवर्ट करें (संख्या) + rest_digits [रहें] ' –

+0

लूपिंग के बजाय रिकर्सन का उपयोग करना आवश्यक नहीं है (यह नहीं कि आपने कहा था)। यह कोड की रेखाओं की संख्या को कम करता है, हालांकि अच्छा जवाब! – martineau

1

आप सवाल "बेस अजगर में 62 रूपांतरण" (या शायद अन्य उत्तर में से एक) को this जवाब में कोड का उपयोग कर सकते हैं।

संदर्भित कोड का उपयोग करना, मुझे लगता है कि इसका जवाब आपके असली सवाल जो था "नाम एक कैश भंडारण के बिना संख्या के आधार पर गणना की जा सकती है कि कैसे?" नाम सरल आधार 62 रूपांतरण बनाने के लिए किया जाएगा संभवतः एक अग्रणी अंडरस्कोर के साथ संख्या का नाम यदि नाम का पहला अक्षर एक अंक है (जिसे नाम को वापस किसी संख्या में परिवर्तित करते समय अनदेखा किया जाता है)।

यहाँ नमूना कोड को दर्शाता हुआ है कि मैं क्या प्रस्ताव है:

from base62 import base62_encode, base62_decode 

def NumberToName(num): 
    ret = base62_encode(num) 
    return ('_' + ret) if ret[0] in '' else ret 

def NameToNumber(name): 
    return base62_decode(name if name[0] is not '_' else name[1:]) 

if __name__ == '__main__': 
    def test(num): 
     name = NumberToName(num) 
     num2 = NameToNumber(name) 
     print 'NumberToName({0:5d}) -> {1!r:>6s}, NameToNumber({2!r:>6s}) -> {3:5d}' \ 
       .format(num, name, name, num2) 

    test(26) 
    test(52) 
    test(53) 
    test(1692) 
    test(23893) 

आउटपुट:

NumberToName( 26) -> 'q', NameToNumber( 'q') -> 26 
NumberToName( 52) -> 'Q', NameToNumber( 'Q') -> 52 
NumberToName( 53) -> 'R', NameToNumber( 'R') -> 53 
NumberToName(1692) -> 'ri', NameToNumber( 'ri') -> 1692 
NumberToName(23893) -> '_6dn', NameToNumber('_6dn') -> 23893 

संख्या नकारात्मक हो सकता है, तो आप संदर्भित जवाब से कोड को संशोधित करना पड़ सकता है (और है कुछ चर्चा कैसे करें इसे कैसे करें)।

2

पहले 10,000 नामों के लिए परीक्षण किया गया:

first_chars = sorted(string.ascii_letters + '_') 
later_chars = sorted(list(string.digits) + first_chars) 

def f(n): 
    # first, determine length by subtracting the number of items of length l 
    # also determines the index into the list of names of length l 
    ix = n 
    l = 1 
    while ix >= 53 * (63 ** (l-1)): 
     ix -= 53 * (63 ** (l-1)) 
     l += 1 

    # determine first character 
    first = first_chars[ix // (63 ** (l-1))] 

    # rest of string is just a base 63 number 
    s = '' 
    rem = ix % (63 ** (l-1)) 
    for i in range(l-1): 
     s = later_chars[rem % 63] + s 
     rem //= 63 

    return first+s 
3

आप क्या मिल गया है bijective numeration का विकृत रूप है (सामान्य उदाहरण स्प्रेडशीट स्तंभ नाम है, जो द्विभाजित आधार -26 रहे हैं किया जा रहा है)।

एक तरह से द्विभाजित संख्यान उत्पन्न करने के लिए:

def bijective(n, digits=string.ascii_uppercase): 
    result = [] 
    while n > 0: 
     n, mod = divmod(n - 1, len(digits)) 
     result += digits[mod] 
    return ''.join(reversed(result)) 

आप सभी इस मामले में जहां 53 >= n > 0 के लिए अंकों का एक अलग सेट की आपूर्ति करने की जरूरत है। तुम भी, 1 से n बढ़ाने के लिए की आवश्यकता होगी के रूप में ठीक से द्विभाजित 0 रिक्त स्ट्रिंग, नहीं "A" है:

def name(n, first=sorted(string.ascii_letters + '_'), digits=sorted(string.ascii_letters + '_' + string.digits)): 
    result = [] 
    while n >= len(first): 
     n, mod = divmod(n - len(first), len(digits)) 
     result += digits[mod] 
    result += first[n] 
    return ''.join(reversed(result))