Why does my string doesn't get modified to one of the values present in the dictionary in Python after length of string becomes equal to key?

Question:

I have a number ‘n’ (n=60, for example), my task is to convert the number into string empty = ‘sixzero’ and calculate the length of string and further modify it in following way, length of ‘sixzero’ is 7 so further modification of the string is ‘seven’, the length of seven is 5 , so further it will be modified to ‘five’ and then length will be 4 so it will be modified to ‘four’ and at this point it should stop because length of string will be 4 and value of string is also ‘four’. I need to return ‘four’ , so Initially I achieved empty = ‘sixzero’ but I am not able to achieve the final result ‘four’. Below is my code.

 class Solution(object):

    # (60)

   def numbers_of_letters(self,n):

       arr = {0:'zero',1:'one',2:'two',3:'three',4:'four',5:'five',
              6:'six',7:'seven',8:'eight',9:'nine'}
       empty = ''
       modi =''

       to_char_array = list(map(int, str(n)))
       for i in range(len(to_char_array)):

            if to_char_array[i] in arr.keys():
                 empty += str(arr.get(to_char_array[i]))
            else:
                 pass
            k=0
            while len(empty) not in arr.values():
                if len(empty) in arr.keys():
                 modi += str(arr.get(k))
                else:
                    pass
       return modi

if __name__ == "__main__":
    n=60
    print(Solution().numbers_of_letters(n))
Asked By: Aurora19

||

Answers:

A trivial recursive approach will give you the answer you need. Note that whatever value is passed to this function, the result will always be ‘four’

MAP = [
    'zero',
    'one',
    'two',
    'three',
    'four',
    'five',
    'six',
    'seven',
    'eight',
    'nine'
]

def as_string(n):
    if n == 0:
        return MAP[0]
    s = []
    while n > 0:
        s.append(MAP[n%10])
        n //= 10
    return ''.join(s)

def number_of_letters(n):
    s = as_string(n)
    if (ls := len(s)) == n:
        return s
    return number_of_letters(ls)

print(number_of_letters(60))

Output:

four

Note:

The as_string() function will return the string, effectively, in reverse. For example, for a value of 60 it would return ‘zerosix’. However, that doesn’t matter because we’re only concerned with the return value’s length.

The integer arithmetic in the as_string() function performs significantly better than any solution involving conversion to and from str <-> int

Alternative:

Using same MAP list:

def as_string(n):
    def _next(n):
        if n == 0:
            yield 0
        while n > 0:
            yield n % 10
            n //= 10
    return ''.join(reversed([MAP[i] for i in _next(n)]))


def number_of_letters(n, rv=None):
    if rv is None:
        rv = list()
    rv.append(s := as_string(n))
    if (ls := len(s)) == n:
        return rv
    return number_of_letters(ls, rv)

print(number_of_letters(60))

Output:

['sixzero', 'seven', 'five', 'four']
Answered By: Fred

Slightly different approach, using two helper functions for each step:

class Solution(object):
    def numbers_of_letters(self,n):
        while True:
            new_n = words_to_number(number_to_words(n))
            if new_n == n:
                break
            else:
                n = new_n
        return number_to_words(new_n)


def words_to_number(words):
    print("".join(words))
    return sum(map(len, words))

def number_to_words(n):
    print(n)
    arr = {0:'zero',1:'one',2:'two',3:'three',4:'four',5:'five',
              6:'six',7:'seven',8:'eight',9:'nine'}
    to_char_array = list(map(int, str(n)))
    words = list(map(lambda x: arr[x], to_char_array))
    return words

if __name__ == "__main__":
    n=60
    print(Solution().numbers_of_letters(n))
Answered By: matszwecja

So an answer in the style of the OP just loops round while the end condition is not true:

class Solution:
    
    def numbers_of_letters(self, n):
        arr = ['zero','one','two','three','four','five','six','seven','eight','nine']

        while True:
           number_as_str = str(n)
           text = ''
           for digit in number_as_str:
               text += arr[int(digit)]
           if len(text) == n:
               return text
           n = len(text)

if __name__ == "__main__":
    n=463829
    print(Solution().numbers_of_letters(n))

Output:

four

And as @Fred pointed out the trivial version is:

class Solution:
    def numbers_of_letters(self, n):
        return 'four'
Answered By: quamrana