HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Returning postal codes between the ones that are given

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thearebetweenreturningcodesthatonesgivenpostal

Problem

I have a function that returns postal codes between the ones given. It works but I feel like I made this over-complicated and there's easy way to make it more simple but I have no idea how.

Inputs are two strings that represents postal codes of my country. They are in the format 'XX-XXX' where X is [0-9]. The task is to return postal codes between them.

Example:

Input: '80-998' '81-003'

Output: '80-998' '80-999' '81-000' '81-001' '81-002' '81-003'

def codes():
    x = '79-900'
    y = '80-155'

    x1 = int(x.split('-')[0])
    x2 = int(x.split('-')[1])
    y1 = int(y.split('-')[0])
    y2 = int(y.split('-')[1])

    while x1 <= y1:
        if x1 == y1:
           while x2 <= y2:
                print ('{}-{:03d}'.format(x1,x2))
                x2 += 1
        else:
            while x2 < 1000:
                print ('{}-{:03d}'.format(x1,x2))
                x2 += 1
        x1 += 1
        x2 = 0

Solution

Reusability

As it stand your code compute zip codes between '79-900' and '80-155'. In case you want to change these bounds, you have to modify the code itself. Which means you can even call this function twice with different bounds within the same program.

You should instead make x and y parameters of the function:

def codes(x, y):
    # Rest of the code


And then you can call it like:

codes('79-900', '80-155')
codes('80-998', '81-003')


You can also benefit from using more descriptive variable names here; like begin and end or start and stop. Same applies for the function name, something like zip_codes_range is more meaningful.
Range

The name zip_codes_range is not chosen arbitrarily. It is because it expand over the name of the range function. And this is because, in the end, zip codes can be viewed as integers and the range function is meant to generate "integers between the ones that are given" (note how this is close to your title).

So the idea is to just parse the zip codes into integers and then feed them to range so it can generate intermediate values:

def int_from_zip(zip_code):
    parts = zip_code.split('-')
    value = ''.join(parts)
    return int(value)

def zip_codes_range(start, stop, step=1):  # Mimic `range` signature
    start = int_from_zip(start)
    stop = int_from_zip(stop)
    for zip_code in range(start, stop+1, step):
        begin = zip_code // 1000
        end = zip_code % 1000
        print('{:02}-{:03}'.format(begin, end))


You could also use begin, end = divmod(zip_code, 1000) instead of the 2 lines process.
Print vs return

To make your function more useful, you should separate concerns. This function should only serves to compute the needed zip codes and return them somehow; the printing of the values being done in another part of the code.

This allow any program using this function to use the value as they intend to, and not necessarily print them.

The first thing you can do is return a list of all the requested values:

def int_from_zip(zip_code):
    return int(''.join(zip_code.split('-')))

def zip_codes_range(start, stop, step=1):
    start = int_from_zip(start)
    stop = int_from_zip(stop)
    return [
        '{:02}-{:03}'.format(*divmod(zip_code, 1000))
        for zip_code in range(start, stop+1, step)
    ]

if __name__ == '__main__':
    for code in zip_codes_range('79-900', '80-155'):
        print(code)


But you could consider using generators, the same way range changed from returning a list in Python 2 to being a generator in Python 3:

def zip_codes_range(start, stop, step=1):
    start = int_from_zip(start)
    stop = int_from_zip(stop)
    for zip_code in range(start, stop+1, step):
        yield '{:02}-{:03}'.format(*divmod(zip_code, 1000))

Code Snippets

def codes(x, y):
    # Rest of the code
codes('79-900', '80-155')
codes('80-998', '81-003')
def int_from_zip(zip_code):
    parts = zip_code.split('-')
    value = ''.join(parts)
    return int(value)


def zip_codes_range(start, stop, step=1):  # Mimic `range` signature
    start = int_from_zip(start)
    stop = int_from_zip(stop)
    for zip_code in range(start, stop+1, step):
        begin = zip_code // 1000
        end = zip_code % 1000
        print('{:02}-{:03}'.format(begin, end))
def int_from_zip(zip_code):
    return int(''.join(zip_code.split('-')))


def zip_codes_range(start, stop, step=1):
    start = int_from_zip(start)
    stop = int_from_zip(stop)
    return [
        '{:02}-{:03}'.format(*divmod(zip_code, 1000))
        for zip_code in range(start, stop+1, step)
    ]


if __name__ == '__main__':
    for code in zip_codes_range('79-900', '80-155'):
        print(code)
def zip_codes_range(start, stop, step=1):
    start = int_from_zip(start)
    stop = int_from_zip(stop)
    for zip_code in range(start, stop+1, step):
        yield '{:02}-{:03}'.format(*divmod(zip_code, 1000))

Context

StackExchange Code Review Q#142183, answer score: 5

Revisions (0)

No revisions yet.