Why is my Python code not working when referencing a dictionary key above 14?

Question:

So i was working on some python code so i could get a better understanding of dictionaries. I have only been learning python 2 weeks and its my first language, so there is definitely a lack of knowledge on my end. I started the program originally to have a user input the section number they were on in a video series and it would output how much time they have left in the entire series. I think expanded on the code to add more output of things like % complete, etc. One of the outputs I added last to the program is to take the section that the user had entered as input and display how long that section is. There are 23 total sections and if the users enters 1-14 then it displays the information accurately. However, if they enter 15-23 then that display line is completely ignored on output. I won’t post the whole code as its too long, but here is some of the relevant info.

Here is the dictionary at the top of the code. The key is the section and the value is the number of minutes in that section. Then you have the only input in the program, followed by the code for showing the length of the selected section.

video_dict = {
    1 : 19, 2 : 54, 3 : 122, 4 : 9, 5 : 75, 6 : 174, 7 : 100, 8 : 81, 9 : 29, 10 : 46, 11 : 138, 12 : 23, 13 : 17, 14 : 143, 15 : 143,
    16 : 24, 17 : 45, 18 : 28, 19 : 3, 20 : 41, 21 : 45, 22 : 15, 23 : 1
}


current_section = int(input('What section are you currently on? (1-23)n'))

# Show how long the selected section is
current_total_time = int(video_dict[current_section])
current_total_minutes = 0
current_total_hours = 0

if current_total_time >= 60:
    current_total_minutes = int(current_total_time % 60)
    current_total_hours = int((current_total_time - current_total_minutes) / 60)
    if current_total_hours == 1:
        if current_total_minutes == 1:
            print(f'Section {current_section} is {current_total_hours} hour and {current_total_minutes} minute long.n')
        elif current_total_minutes >= 2:
            print(f'Section {current_section} is {current_total_hours} hour and {current_total_minutes} minutes long.n')
        elif current_total_minutes == 0:
            print(f'Section {current_section} is {current_total_hours} hour long.n')
    elif current_total_hours >= 2:
        if current_total_minutes == 1:
            print(f'Section {current_section} is {current_total_hours} hours and {current_total_minutes} minute long.n')
        elif current_total_minutes >= 2:
            print(f'Section {current_section} is {current_total_hours} hours and {current_total_minutes} minutes long.n')
        elif current_total_minutes == 0:
            print(f'Section {current_section} is {current_total_hours} hours long.n')
elif (current_total_time > 0) and (current_total_time < 60):
    if current_total_minutes == 1:
        print(f'Section {current_section} is {current_total_minutes} minute long.n')
    elif current_total_minutes >= 2:
        print(f'Section {current_section} is {current_total_minutes} minutes long.n')

As a side note, I know this code is probably a little too verbose but at my current stage in learning this is where i’m at. Would there be a shorter way to type this code so that I could clean it up a little? You don’t have to type an example, unless you want to, you can just say what commands i should be looking at in python and learning to accomplish this. Thank you for your input.

Asked By: Showtunes

||

Answers:

The whole thing can just be this:

video_dict = {
    1 : 19, 2 : 54, 3 : 122, 4 : 9, 5 : 75, 6 : 174, 7 : 100, 8 : 81, 9 : 29, 10 : 46, 11 : 138, 12 : 23, 13 : 17, 14 : 143, 15 : 143,
    16 : 24, 17 : 45, 18 : 28, 19 : 3, 20 : 41, 21 : 45, 22 : 15, 23 : 1
}

current_section = int(input('What section are you currently on? (1-23)n'))

# Show how long the selected section is
current_total_time = int(video_dict[current_section])
current_total_minutes = 0
current_total_hours = 0

current_total_minutes = int(current_total_time % 60)
current_total_hours = int((current_total_time - current_total_minutes) / 60)
if current_total_time >= 60:
    print(f'Section {current_section} is {current_total_hours} hour and {current_total_minutes} minute long.n')
else:
    print(f'Section {current_section} is {current_total_minutes} minute long.n')

Since you only have 2 cases.

Case 1: when the total time is 60 minutes or more.

Case 2: when the total time is less than 60 minutes.

As to why your code is not working

Move the following lines outside of your if block.

    current_total_minutes = int(current_total_time % 60)
    current_total_hours = int((current_total_time - current_total_minutes) / 60)

So it would look like this

current_total_minutes = int(current_total_time % 60)
current_total_hours = int((current_total_time - current_total_minutes) / 60)
if current_total_time >= 60:
    if current_total_hours == 1:
        if current_total_minutes == 1:
 # Rest of your code here

For instance, section 1 has a current_total_time of 19, therefore it would not satisfy the condition in the if-statement if current_total_time >= 60. Thus, current_total_minutes and current_total_hours will remain 0, since they will only change if the aforementioned condition is evaluated to True.

And lastly, in your elif block:

elif (current_total_time > 0) and (current_total_time < 60):
    if current_total_minutes == 1:
        print(f'Section {current_section} is {current_total_minutes} minute long.n')
    elif current_total_minutes >= 2:
        print(f'Section {current_section} is {current_total_minutes} minutes long.n')

The condition if current_total_minutes == 1 will never evaluate to True, thus never printing anything.

Have fun learning.

Answered By: mudi loodi

Problem: init to 0 + assignment inside if-block

The culprit code is this:

current_total_minutes = 0
current_total_hours = 0

if current_total_time >= 60:
    current_total_minutes = int(current_total_time % 60)
    current_total_hours = int((current_total_time - current_total_minutes) / 60)

The variables are initialised to zero, and then only changed if the total time is >= 60; when the program gets down to the elif, the minutes and hours variables are still 0. Instead, initialise the variables outside and before the if-block, because the values will stay the same regardless, something like this:

current_total_minutes = current_total_time % 60
current_total_hours   = current_total_time // 60

if ... # etc

Other suggestions:

divmod instead of int(a % b) and int(a / b)

This is one of those things where, as you use a language more and more, you become familiar with the built-in functions & modules that are available, without having to re-roll your own solution. You’re trying to take some number (a total) and divide it by 60, to get both the whole part (hours) and remainder (minutes). There’s a function for that! You might use the divmod function; its docstring says

divmod(x, y, /)
    Return the tuple (x//y, x%y).  Invariant: div*y + mod == x.

Assembled f-string

I’d suggest using conditional expressions to build up the final string, instead of nested if-else blocks, especially where logic for "hour(s)" or "minute(s)" need to be repeated. This way, the program decides once whether to print "", "1 minute", or "x minutes" (and similarly "", "1 hour and ", or "x hours and "), and then puts the pieces together once.

For example, instead of

if minutes == 0:
    # leave minutes part blank
elif minutes == 1:
    # print "1 minute"
elif minutes > 1:
    # print "# minutes"

you could equivalently write

"" if not minutes else f"{minutes} minute{'s' if minutes > 1 else ''}"

To break the above down — it’s a nested conditional statement.
which gives either

  • an empty string ("" if not minutes)
  • "1 minute" (else f"{minutes} minute...), or
  • "x minutes" ({'s' if minutes > 1 else ''} adds the s if it’s needed)

Example changes

All put together:

times = [ 19, 54,122,  9, 75,174,
         100, 81, 29, 43,138, 23,
          17,143,143, 24, 45, 28,
           3, 41, 45, 15,  1,    ]

# dict comprehension expression
video_dict = {idx: val for idx, val in enumerate(times, 1)}

section = int(input('What section are you currently on? (1-23)n'))

# Show how long the selected section is
total = video_dict[section]
hours, minutes = divmod(total, 60) # tuple expansion

hours_str = "" if not hours else f"{hours} hour{'s' if hours > 1 else ''} and "
minutes_str = "" if not minutes else f"{minutes} minute{'s' if minutes > 1 else ''}"

section_str = f"Section {section} is {hours_str}{minutes_str} long.n"
print(section_str)
Answered By: Joshua Voskamp
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.