How to convert a loop to a list in Python - a specific puzzle

This code, if you give it the number N, generates 1234 ... N or N ... 4321, but outputs the result not as a string, but rather as a number. I wanted to convert the loop in the middle to a list comprehension but ran into difficulty trying to do this.

Here's the code that works (written in Python 2.7:

def findTens(N):
    # counts number of tens in a number: examples:  
    #   * 100 & 113 would both return 2
    #   * 9 returns 0
    #   * 14 returns 1

    incrementer = 1
    while True:
        if N - 10**incrementer < 0:
            break
        else:
            incrementer += 1

        if incrementer == 100:  
            break   # debugging condition
    return incrementer - 1

def create_seqNum(N, reverse=False, showWork=False, returnDescr=False, divLength=100):
    '''create_seqNum() --> iput N, and get back a number built from the sequence of 1234...N
Arguments: reverse=True to get the sequence in revers, showWork=True to see numbers that add up to final,
returnDescr=True to print the answer in a sentence as well as returning it as a number.'''

    num = 0
    tensIncr = 0
    answer = 0
    Ntens = findTens(N)
    modifier = 0            # modifies counter when increment of 10 occurs
    if reverse == True:     # create range builder inputs
        rstart = 1
        rend = N+1
        rinc = 1
    else:
        rstart = N
        rend = 0
        rinc = -1
    for i in range(rstart, rend, rinc):
        itens = findTens(i)
        num = i * 10**tensIncr        
        tensIncr += 1 + itens
        pad = (Ntens - itens)
        if showWork == True:
            print(("For %d" + " "*pad + " Add: %d") %(i, num))    
        answer += num

    if showWork == True:
        print("#"*divLength)

    if showWork == True or returnDescr == True:
        print("Answer: %d" %answer)
        print("#"*divLength)

    return answer

      

All of these test cases work with the above code:

for i in [1, 5, 9, 10, 11, 13, 98, 99, 100, 101, 102, 107, 1012]:
    create_seqNum(i, reverse=True, returnDescr=True)
    create_seqNum(i, returnDescr=True)

      

Note also that my attempt to create a worklist comprehension broke both to break out of the loop in the calculation and to get a list of added numbers as well as the grand total ("showWork" option), but if no one breaks them then the best decision will be made for a calculation that will pass all tests.

In case it helps - here is my attempt at converting it to a list of issues that failed. If someone can figure this out by trying to find out from your answer and thought others might find the puzzle of this interesting (at least I hope):

def create_seqNum_v2(N, reverse=False, showWork=False, returnDescr=False, divLength=100):
    '''create_seqNum() --> iput N, and get back a number built from the sequence of 1234...N
Arguments: reverse=True to get the sequence in revers, showWork=True to see numbers that add up to final,
returnDescr=True to print the answer in a sentence as well as returning it as a number.'''

    num = 0
    tensIncr = 0
    answer = 0
    Ntens = findTens(N)
    modifier = 0            # modifies counter when increment of 10 occurs
    if reverse == True:     # create range builder inputs
        rstart = 1
        rend = N+1
        rinc = 1
    else:
        rstart = N
        rend = 0
        rinc = -1

    workList = [i * 10**((i-1) + findTens(i)) for i in range(rstart, rend, rinc)]
    answer = sum(workList)

    if showWork == True:
        # [ print(("For %d" + " "*(Ntens - findTens(i)) + " Add: %s") %(workList[i], i)) for i in workList ]    
        # [x for ind, x in enumerate(list1) if 4 > ind > 0]
        [print(("%d" + " "*(Ntens-findTens(x)) + ": %s") %(ind, x)) for ind, x in enumerate(workList)]

    if showWork == True:
        print("#"*divLength)

    if showWork == True or returnDescr == True:
        print("Answer: %d" %answer)
        print("#"*divLength)

    return answer

      

Source and background of this problem:

In HackerRank, you have an N = 123 ... N solution, just not using strings, and they take a simple one-line print format operator as the answer. While using python 3.x print arguments in connection with list unpacking is much more efficient for solving this problem, I wondered if it was possible to plot a number as a number without any string conversions to do it. Since print()

I think it is converted to a string under the covers before it outputs content, I felt this was a more interesting approach, from a purely academic point of view.

+3


source to share


6 answers


It can be done in one line (minus imports), in no more than O (n) steps, without writing separate functions or loops, just a standard map shorthand.

import math # to get math.log10
listofints = [1,2,3,10,12,19,99,100,101,50102030]
n = reduce(lambda x,y:[x[0]*(10**(y[1]+1))+y[0],0],map(lambda x:[x,int(math.log10(x))], listofints))[0]
print(n)

# the number 1231012199910010150102030

      

This uses the standard map-reduce method to decorate numbers using a map and then flattens them back to a number.

First step:

map(lambda x:[x,int(math.log10(x))], ...

      

accepts a list of integers such as:

[1,2,3,10,12,19,99,100,101,50102030]

      

and converts them to a list of pairs that are a number plus the base-10 logarithm:

[[1, 0], [2, 0], [3, 0], [10, 1], [12, 1], [19, 1], [99, 1], [100, 2], [101, 2], [50102030, 7]]

      



Then the next step is to reduce this list to one number:

reduce(lambda x,y:[x[0]*(10**(y[1]+1))+y[0],0],...

      

To do this, you need to multiply it by ten to make room for the next number to be added. Fortunately, the next number tells you how big it is. So multiply the pair by one number (first part) by 10 by (one plus) by the cardinality of the next pair (second part), and then add the second number of the pair (first part).

The reduction looks like this:

[[1, 0], [2, 0], [3, 0], [10, 1], [12, 1], [19, 1], [99, 1], [100, 2], [101, 2], [50102030, 7]]
[[12, 0], [3, 0], [10, 1], [12, 1], [19, 1], [99, 1], [100, 2], [101, 2], [50102030, 7]]
[[123, 0], [10, 1], [12, 1], [19, 1], [99, 1], [100, 2], [101, 2], [50102030, 7]]
[[12310, 0], [12, 1], [19, 1], [99, 1], [100, 2], [101, 2], [50102030, 7]]
[[1231012, 0], [19, 1], [99, 1], [100, 2], [101, 2], [50102030, 7]]
[[123101219, 0], [99, 1], [100, 2], [101, 2], [50102030, 7]]
[[12310121999, 0], [100, 2], [101, 2], [50102030, 7]]
[[12310121999100, 0], [101, 2], [50102030, 7]]
[[12310121999100101, 0], [50102030, 7]]
[[1231012199910010150102030, 0]]

      

Finally, the last element is [1231012199910010150102030, 0], so take its first element which is 1231012199910010150102030

UPDATE

While the whole job of reducing the number of cards is a good process to get used to, it was too much. This can be done without the entire map by simply using the shorthand:

n = reduce(lambda x,y:x*(10**(int(math.log10(y))+1))+y,listofints)

      

+2


source


So it looks like cancer, but I think it works



def get_seq(n):
    return sum([(m+1)*10**(m + [sum([k/10 for k in range(n)][:i+1]) for i in range(len([j/10 for j in range(n)]))][m]) for m in range(n)])

      

0


source


I'm not entirely sure I understand your problem, but are you looking for something like this?

def create_seqNum(num, reverse=False):
    final_num = 0
    x = [x for  x in range(1, num+1)]
    y = [y for y in range(num, 0, -1)]
    for i in range(0, num):
        print(x[i], y[i])
        final_num += x[i]* 10**(y[i]-1)

    return final_num

      

0


source


I may have misunderstood, but what about:

def msb(N):
    return sum(((i+1)*10**i for i in xrange(N)))

      

and

def lsb(N):
    return sum(((i+1)*10**(N-i-1) for i in xrange(N)))

      

This fails if N> = 10.

0


source


How about this:

def reverse(N):
    return sum([(x + 1) * 10**x for x in range(N)])

def forwards(N):
    return sum([(x+1) * 10**y for x, y in zip(range(N), range(N-1, -1, -1))])

      

0


source


This is true only for 1 <= N <= 9, but you can see that the square root of numbers like 1234 ... N ... 4321 is N units.

def seq(n):
    return reduce(lambda x,y: 10*x+y, [1]*n)**2/10**(n-1)

      

0


source







All Articles