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.
CodePudding user response:
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.
CodePudding user response:
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 thes
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)