1

I have too many if statements and I have a hard time understanding the dictionary system.

It seems like an easy fix, but everything I try I make it worse.

    """
    Find the place where the person was born.

    Possible locations are following: Kuressaare, Tartu, Tallinn, Kohtla-Järve, Narva, Pärnu,
    Paide, Rakvere, Valga, Viljandi, Võru and undefined. Lastly if the number is incorrect the function must return
    the following 'Wrong input!'
    :param birth_number: int
    :return: str
    """
    return 
    if not is_valid_birth_number(birth_number):
        return "Wrong input!"
    if 10 >= birth_number >= 1:
        return "Kuressaare"
    elif 20 >= birth_number >= 11:
        return "Tartu"
    elif 220 >= birth_number >= 21:
        return "Tallinn"
    elif 270 >= birth_number >= 221:
        return "Kohtla-Järve"
    elif 370 >= birth_number >= 271:
        return "Tartu"
    elif 420 >= birth_number >= 371:
        return "Narva"
    elif 470 >= birth_number >= 421:
        return "Pärnu"
    elif 490 >= birth_number >= 471:
        return "Tallinn"
    elif 520 >= birth_number >= 491:
        return "Paide"
    elif 570 >= birth_number >= 521:
        return "Rakvere"
    elif 600 >= birth_number >= 571:
        return "Valga"
    elif 650 >= birth_number >= 601:
        return "Viljandi"
    elif 710 >= birth_number >= 651:
        return "Võru"
    elif 999 >= birth_number >= 711:
        return "undefined"

Need to get rid of idcode.py:149:1: C901 'get_birth_place' is too complex (16) error.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Martin
  • 23
  • 1
  • 6
  • It seems like you have pairs of numbers mapping to strings, so try a dictionary `{(1, 10): "Kuressaare", ...}`. – jonrsharpe Sep 24 '19 at 21:04
  • 3
    Looks like a task for [`bisect`](https://docs.python.org/3/library/bisect.html) and a dictionary. – Matthias Sep 24 '19 at 21:05
  • @jonrsharpe How would you use that with an input like `5`, which is in between? – Barmar Sep 24 '19 at 21:05
  • @Barmar at the simplest you just iterate over keys until you get a match. If that proves insufficiently performant, you could trade space for time by expanding all the inbetween values and having repeated values. – jonrsharpe Sep 24 '19 at 21:06
  • 1
    Have a look at [this post](https://stackoverflow.com/a/2899190/6340496) which uses the `bisect` module. – S3DEV Sep 24 '19 at 21:09
  • 1
    @S3DEV: That's a nice one. – Matthias Sep 24 '19 at 21:39

4 Answers4

3

Use a list that maps the end of each range to the return value.

if not is_valid_birth_number(birth_number):
    return "Wrong input!"

locations = [(10, "Kuressaare"), (220, "Tartu"), (270, "Tallinn"), ...]
for limit, loc in locations:
    if birth_number <= limit:
        return loc

You don't need the beginning and end of each range, because they're in order. Just the end of the range is enough.

Barmar
  • 741,623
  • 53
  • 500
  • 612
3

An example with bisect.

import bisect

locations = {
    1: 'Kuressaare',
    2: 'Tartu',
    3: 'Tallinn',
    4: 'Kohtla-Järve',
    5: 'Tartu'
}

birth_number_levels = [1, 11, 21, 221, 271, 371]
position = bisect.bisect(birth_number_levels, birth_number)
return locations[position]

I prefer keeping data together as @Barmar did. This leads to:

import bisect

locations = [
    (10, 'Kuressaare'),
    (20, 'Tartu'),
    (220, 'Tallinn'),
    (270, 'Kohtla-Järve'),
    (370, 'Tartu')
]
birth_number_levels = [location[0] for location in locations]
position = bisect.bisect_left(birth_number_levels, birth_number)
return locations[position][1]
Matthias
  • 12,873
  • 6
  • 42
  • 48
0

I'd go with a dictionary, which contains keys as ranges and the value is the name of location. Then iterate over it checking if the given birth_number is in the key.

Basically:

loc_dict = {
    range(1, 11): "Kuressaare",
    range(11, 21): "Tartu",
    etc...
}

for loc_range, loc_name in loc_dict.items():
    if birth_number in loc_range:
        return loc_name

I think that's a pretty clear way of handling that.

robscott
  • 91
  • 7
0

It's easier to loop through a list than to have to code specific if statements, plus this can be completely dynamic.

def bd(birth_number):
    x = ((10,"Kuressaare"),(20,"Tartu"),(220,"Tallinn"),(270,"Tartu"),(370,"Kohtla-Järve"),(420,"Tartu"),(470,"Narva"),(490,"Pärnu"),(520,"Tallinn"),(570,"Paide"),(600,"Rakvere"))
    if not isinstance(birth_number, (int, long)):
        return "Wrong input!"
    for i in x:
        if birth_number<= i[0]:
            return i[1]
    return "undefined"

print(bd(300))
eatmeimadanish
  • 3,809
  • 1
  • 14
  • 20