2
\$\begingroup\$

A little context:

  • Book has 411 Pages

  • Read a random number of pages on the first day which is unknown

  • Number of pages to read next day is the square of the sum of the digits of the page currently on

    I.e. on Page 36: read 81 pages next day

  • On day 6 The square answer directly adds to current page number to make 411

  • Finish Book

How many pages did she read on the first day and how many pages did she read on the 6 days?

This is what I have so far:

from itertools import accumulate, count

def read_book( start ):
    for i in range( 6 ): yield start; start += sum( int( digit ) for digit in str( start ) ) ** 2

def find_start( pages ):
    for start in count( 1 ):
        for read in read_book( start ): pass
        if read == pages: return start

previous_answer, start = 0, find_start( 411 )
for i, read in enumerate( read_book( start ), 1 ):
    print( "Pages read on day", i ,"was", read-previous_answer ,"\t(Now on page", str(read) + ")\n")
    previous_answer += read-previous_answer

Output:

Pages read on day 1 was 61 (Now on page 61)

Pages read on day 2 was 49 (Now on page 110)

Pages read on day 3 was 4 (Now on page 114)

Pages read on day 4 was 36 (Now on page 150)

Pages read on day 5 was 36 (Now on page 186)

Pages read on day 6 was 225 (Now on page 411)

Is there a more efficient way of writing this using fewer lines of code?

\$\endgroup\$
  • \$\begingroup\$ Welcome to CR.SE! Unless you are looking for a review of your code, this is not the correct place for such a question. Perhaps consider posting to code golf or similar. \$\endgroup\$ – psaxton Jan 10 '15 at 20:23
  • \$\begingroup\$ Okay... Well is this an efficient way of doing the task: if so how would you change it. I have submitted a post in Code-Golf for least no. character answer. But I would like people to answer on here to see if what I have made is good also... If anyone can review my code (not that of others) and suggest corrections/improvements please feel free to share! thanks \$\endgroup\$ – user62630 Jan 10 '15 at 20:47
3
\$\begingroup\$

Can someone see if there is a more efficient way of writing this using fewer lines of code?

I suppose your focus is not literally on the part about "fewer lines of code". You could use more semicolons to squeeze more lines onto a single line, but that would violate PEP 20, the Zen of Python, even more than it already does.

Your current solution is essentially a brute force algorithm, counting up from the beginning until you find a suitable start page from which the last page will be reached on Day 6. The algorithm is well implemented, and I don't know a better way. I can suggest some other improvements though.

Coding style

You should follow PEP8, the Python coding style guide. In particular:

  • Do break lines in loops
  • Avoid using semicolon to separate multiple statements
  • Don't put spaces around method parameters, for example write read_book(start) instead of read_book( start )

Generalize

It would be nice to make the implementation more general.

For example, the target pages 411 and the required number of days would be nice to put in constants, to make them easier to play with and less magic.

Also, instead of executing code in the global namespace, the best practice is wrap your main code in a main() method, and call that from within if __name__ == '__main__':, like this:

def main():
    # main implementation

if __name__ == '__main__':
    main()

Robustness

The find_start method counts up from 1 until the target page is reached, or else...forever. It would better to set an upper limit, like this:

def find_start(pages):
    for start in range(1, pages):
        read = start
        for read in read_book(start):
            pass
        if read == pages:
            return start
    raise ValueError("Impossible to reach page {} exactly".format(pages))

Suggested implementation

Putting the above suggestions together:

PAGES = 411
DAYS_TO_READ = 6


def read_book(start):
    for _ in range(DAYS_TO_READ):
        yield start
        start += sum(int(digit) for digit in str(start)) ** 2


def find_start(pages):
    for start in range(1, pages):
        read = start
        for read in read_book(start):
            pass
        if read == pages:
            return start
    raise ValueError("Impossible to reach page {} exactly".format(pages))


def main():
    previous_answer, start = 0, find_start(PAGES)
    for i, read in enumerate(read_book(start), 1):
        print("Pages read on day {} was {}\t(Now on page {})\n".format(
            i, read - previous_answer, read))
        previous_answer += read - previous_answer


if __name__ == '__main__':
    main()
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy