Python3 - Advice on a while loop with range? - python-3.x

Good afternoon! I am relatively new to Python - and am working on an assignment for a class.
The goal of this code is to download a file, add a line of data to the file, then create a while loop that iterates through each line of data, and prints out the city name and the highest average temp from the data for that city.
My code is below - I have the output working, no problem. The only issue I am running into is an IndexError: list index out of range - at the end.
I have searched on StackOverflow - as well as digging into the range() function documentation online with Python. I think I just need to figure to the range() properly, and I'd be done with it.
If I take out the range, I get the same error - so I tried to change the for/in to - for city in mean_temps:
The result of that was that the output only showed 4 of the 7 cities - skipping every other city.
Any advice would be greatly appreciated!
here is my code - the screenshot link below shows output and the error as well:
!curl https://raw.githubusercontent.com/MicrosoftLearning/intropython/master/world_temp_mean.csv -o mean_temp.txt
mean_temps = open('mean_temp.txt', 'a+')
mean_temps.write("Rio de Janeiro,Brazil,30.0,18.0")
mean_temps.seek(0)
headings = mean_temps.readline().split(',')
print(headings)
while mean_temps:
range(len(city_temp))
for city in mean_temps:
city_temp = mean_temps.readline().split(',')
print(headings[0].capitalize(),"of", city_temp[0],headings[2], "is", city_temp[2], "Celsius")
mean_temps.close()

You have used a while loop, when you actually want to use a for loop. You have no condition on your while loop, therefore, it will evaluate to True, and run forever. You should use a for loop in the pattern
for x in x:
do stuff
In your case, you will want to use
for x in range(len(city_temp)):
for city in means_temp:
EDIT:
If you have to use a while loop, you could have variable, x, that is incremented by the while loop. The while loop could run while x is less than range(len(city_temp)).
A basic example is
text = "hi"
counter = 0
while counter < 10:
print(text)
counter += 1
EDIT 2:
You also said that they expected you to get out of a while loop. If you want a while loop to run forever unless a condition is met later, you can use the break command to stop a while or for loop.

I've been stuck with this as well with the index error. My original code was:
city_temp = mean_temp.readline().strip(" \n").split(",")
while city_temp:
print("City of",city_temp[0],headings[2],city_temp[2],"Celcius")
city_temp = mean_temp.readline().split(",")
So I read the line then, in the loop, print the line, create the list from reading the line and if the list is empty, or false, break. Problem is I was getting the same error as yourself and this is because city_temp is still true after reading the last line. If you add..
print(city_temp)
to your code you will see that city_temp returns as "" and even though it's an empty string the list has content so will return true. My best guess (and it is a guess) it looks for the split condition and returns back nothing which then populates the list as an empty string.
The solution I found was to readline into a string first (or at the end of the whole loop) before creating the list:
city_temp = mean_temp.readline()
while city_temp:
city_temp = city_temp.split(',')
print(headings[0].capitalize(),"of",city_temp[0],headings[2],"is",city_temp[2],"Celcius")
city_temp = mean_temp.readline()
This time city_temp is checked by the while loop as a string and now returns false. Hope this helps from someone else who struggled with this

Related

Python function looping through a dictionary of sets removing and adding items updating only some items

Thanks in advance for your assistance.
I have two dictionaries: parent_dict has a series of sets as values & pub_plat_dict is a look-up dictionary that seeks to correct the names of the items that make up the sets in parent_dict.
The function update_dict allows names where it finds a '.' to pass. If it doesn't find a name then it will try to find the name in the pub_plat_dict. If found it will .remove the old name and .add the updated name. If the name isn't present, then I want the program to move to the next item.
When I run the function update_dict corrects the first item in the parent_dict, accurately skips multiple items that don't need to be updated but then doesn't .remove or .add the other wrongly named items.
Sample Data
parent_dict = {
'49d238407e0102ba':{'opportunity_history'}
, 'f9d53c74ec1d2ff6':{'servicer.trial_balance','src_platform.loan','src_platform.loan_disbursement'}
, 'fc35a98e0cfaab3d':{'loan', 'loan_agreement', 'opportunity_compliance_flag','zodiac'}
}
pub_plat_dict = {'loan':'src_platform.loan',
'opportunity_compliance_flag':'src_platform.opportunity_compliance_flag',
'opportunity_history':'src_platform.opportunity_history',
'loan_agreement': 'src_platform_mosaic_live.loan_agreement'}
Function
def update_dict(parent_dict):
for tbls in parent_dict.values():
for tbl in tbls:
if tbl.find(".") != -1:
pass
else:
try:
update = pub_plat_dict[tbl]
tbls.remove(tbl)
tbls.add(update)
except:
pass
return(parent_dict)
Output
{'49d238407e0102ba': {'src_platform.opportunity_history'}, 'f9d53c74ec1d2ff6': {'src_platform.loan', 'src_platform.loan_disbursement', 'servicer.trial_balance'}, 'fc35a98e0cfaab3d': {'opportunity_compliance_flag', 'loan_agreement', 'loan', 'zodiac'}}
NOTE: the first item is updated correctly but everything else is left unchanged.
I did the following loop to try to figure out my error (keeping it as close to the update_dict code as I could).
for tbls in parent_dict.values():
for tbl in tbls:
if tbl.find('.') != -1:
print("UNCHANGED-" + tbl)
else:
try:
print("CHANGED-" + pub_plat_dict[tbl])
except:
print("FAILURE-"+ tbl)
It gives me the following output:
UNCHANGED-src_platform.opportunity_history
UNCHANGED-src_platform.loan
UNCHANGED-src_platform.loan_disbursement
UNCHANGED-servicer.trial_balance
CHANGED-src_platform.opportunity_compliance_flag
CHANGED-src_platform_mosaic_live.loan_agreement
CHANGED-src_platform.loan
FAILURE-zodiac
Aside from the capitalized- word this is what I would expect the parent_dict would now look like. So my .remove and .add aren't working consistently.
EDIT: I also substituted .discard for .remove, the output did not change.
Any assistance would be greatly appreciated.
I couldn't get the function to work as I created it. Part of the issue is where the return statement appears. Using a return inside of a loop will break it and exit the function even if the iteration is still not finished. Another issue might be the redundant logic in the function.
I decided to create a new dictionary and use a list as the dict's values instead of sets. I simplified the logic in the function and got rid of the if statement which seemed redundant in light of the try clause.
from collections import defaultdict
cln_parent_dict = defaultdict(list)
def update_dict(parent_dict):
for key in parent_dict:
for value in parent_dict[key]:
try:
cln_parent_dict[key].append(pub_plat_dict[value])
except:
cln_parent_dict[key].append(value)
return(cln_parent_dict)
when I run the function I get what I expect:
Function Output
defaultdict(<class 'list'>, {'49d238407e0102ba': ['src_platform.opportunity_history'], 'f9d53c74ec1d2ff6': ['servicer.trial_balance', 'src_platform.loan_disbursement', 'src_platform.loan'], 'fc35a98e0cfaab3d': ['zodiac', 'src_platform_mosaic_live.loan_agreement', 'src_platform.opportunity_compliance_flag', 'src_platform.loan']})
Overall the change seems to work for the 100K items in the dataset.
Thanks to everyone for taking a look.

Remove & add split-list using dictionary python [duplicate]

I have the code below. I'm trying to remove two strings from lists predict strings and test strings if one of them has been found in the other. The issue is that I have to split up each of them and check if there is a "portion" of one string inside the other. If there is then I just say there is a match and then delete both strings from the list so they are no longer iterated over.
ValueError: list.remove(x): x not in list
I get the above error though and I am assuming this is because I can't delete the string from test_strings since it is being iterated over? Is there a way around this?
Thanks
for test_string in test_strings[:]:
for predict_string in predict_strings[:]:
split_string = predict_string.split('/')
for string in split_string:
if (split_string in test_string):
no_matches = no_matches + 1
# Found match so remove both
test_strings.remove(test_string)
predict_strings.remove(predict_string)
Example input:
test_strings = ['hello/there', 'what/is/up', 'yo/do/di/doodle', 'ding/dong/darn']
predict_strings =['hello/there/mister', 'interesting/what/that/is']
so I want there to be a match between hello/there and hello/there/mister and for them to be removed from the list when doing the next comparison.
After one iteration I expect it to be:
test_strings == ['what/is/up', 'yo/do/di/doodle', 'ding/dong/darn']
predict_strings == ['interesting/what/that/is']
After the second iteration I expect it to be:
test_strings == ['yo/do/di/doodle', 'ding/dong/darn']
predict_strings == []
You should never try to modify an iterable while you're iterating over it, which is still effectively what you're trying to do. Make a set to keep track of your matches, then remove those elements at the end.
Also, your line for string in split_string: isn't really doing anything. You're not using the variable string. Either remove that loop, or change your code so that you're using string.
You can use augmented assignment to increase the value of no_matches.
no_matches = 0
found_in_test = set()
found_in_predict = set()
for test_string in test_strings:
test_set = set(test_string.split("/"))
for predict_string in predict_strings:
split_strings = set(predict_string.split("/"))
if not split_strings.isdisjoint(test_set):
no_matches += 1
found_in_test.add(test_string)
found_in_predict.add(predict_string)
for element in found_in_test:
test_strings.remove(element)
for element in found_in_predict:
predict_strings.remove(element)
From your code it seems likely that two split_strings match the same test_string. The first time through the loop removes test_string, the second time tries to do so but can't, since it's already removed!
You can try breaking out of the inner for loop if it finds a match, or use any instead.
for test_string, predict_string in itertools.product(test_strings[:], predict_strings[:]):
if any(s in test_string for s in predict_string.split('/')):
no_matches += 1 # isn't this counter-intuitive?
test_strings.remove(test_string)
predict_strings.remove(predict_string)

Python loop list in function call

This is my first question on StackOverflow. I have always found what I was looking for just googling, but this time I'm stuck and can't figure it out.
I'm a beginner programmer with python and still learning a lot.
I want to change a dateEdit box in a Userinterface with a small code to set det current date time.
the code looks like this.
self.dateEdit_2.setDateTime(QtCore.QDateTime.currentDateTime())
Now i want to change every dateEdit box the same, starting from 2 and going to 29, without typing every single line out.
i have tried to make a for loop with a filled list.
and i get it to print out what i want, but how does i get "set_date_numb" to be a attribute that does what i want.
hope you understand, Thanks.
dateTimeList = ['2','3','4','5','6','7','8','9',
'10','11','12','13','14','15','16','17','18','19','20',
'21','22','23','24','25','26','27','28','29']
indexval = 0
for i in range(len(dateTimeList)):
date_numb = (dateTimeList[indexval])
set_date_numb ='self.dateEdit_{}.setDateTime(QtCore.QDateTime.currentDateTime())'.format(date_numb)
print(set_date_numb)
indexval += 1
You could use getattr(), see the documentation here. Since the functions you are after are members of your instance you can grab them with their names as strings (which I think is the main problem you are facing):
dateTimeList = [str(x) for x in range(2,30)]
for dt in dateTimeList:
name = "dateEdit_{}".format(dt)
currentDateEdit = getattr(self, name)
currentDateEdit.setDateTime(QtCore.QDateTime.currentDateTime())

Saving ord(characters) from different lines(one string) in different lists

i just can't figure it out.
I got a string with some lines.
qual=[abcdefg\nabcedfg\nabcdefg]
I want to convert my characters to the ascii value and saves those values in an other list for each line.
value=[[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6]
But my codes saves them all in one list.
values=[1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6]
First of all my code:
for element in qual:
qs = ord(element)
quality_code.append(qs)
I also tried to split() the string but the result is still the same
qual=line#[:-100]
qually=qual.split()
for list in qually:
for element in list:
qs = ord(element)
quality.append(qs)
My next attempt was:
for element in qual:
qs = ord(element)
quality_code.append(qs)
for position in range(0, len(quality_code)):
qual_liste[position].append(quality_code[position])
With this code an IndexError(list index out of range) occurs.
There is probably a way with try and except but i dont get it.
for element in qual:
qs = ord(element)
quality_code.append(qs)
for position in range(0, len(quality_code)):
try:
qual_liste[position].append(quality_code[position])
except IndexError:
pass
With this code the qual_lists stays empty, probably because of the pass
but i dont know what to insert instead of pass.
Thanks a lot for help. I hope my bad english is excusable .D
Here you go, this should do the trick:
qual="abcdefg\nabcedfg\nabcdefg"
print([[ord(ii) for ii in i] for i in qual.split('\n')])
List comprehension is always the answer.

Updating dictionary - Python

total=0
line=input()
line = line.upper()
names = {}
(tag,text) = parseLine(line) #initialize
while tag !="</PLAY>": #test
if tag =='<SPEAKER>':
if text not in names:
names.update({text})
I seem to get this far and then draw a blank.. This is what I'm trying to figure out. When I run it, I get:
ValueError: dictionary update sequence element #0 has length 8; 2 is required
Make an empty dictionary
Which I did.
(its keys will be the names of speakers and its values will be how many times s/he spoke)
Within the if statement that checks whether a tag is <SPEAKER>
If the speaker is not in the dictionary, add him to the dictionary with a value of 1
I'm pretty sure I did this right.
If he already is in the dictionary, increment his value
I'm not sure.
You are close, the big issue is on this line:
names.update({text})
You are trying to make a dictionary entry from a string using {text}, python is trying to be helpful and convert the iterable inside the curly brackets into a dictionary entry. Except the string is too long, 8 characters instead of two.
To add a new entry do this instead:
names.update({text:1})
This will set the initial value.
Now, it seems like this is homework, but you've put in a bit of effort already, so while I won't answer the question I'll give you some broad pointers.
Next step is checking if a value already exists in the dictionary. Python dictionaries have a get method that will retrieve a value from the dictionary based on the key. For example:
> names = {'romeo',1}
> print names.get('romeo')
1
But will return None if the key doesn't exist:
> names = {'romeo',1}
> print names.get('juliet')
None
But this takes an optional argument, that returns a different default value
> names = {'romeo',2}
> print names.get('juliet',1)
1
Also note that your loop as it stands will never end, as you only set tag once:
(tag,text) = parseLine(line) #initialize
while tag !="</PLAY>": #test
# you need to set tag in here
# and have an escape clause if you run out of file
The rest is left as an exercise for the reader...

Resources