Dictionary won't store the value after restart - python

Here is my code. This code is for managing fruit stocks in the shop. So you type in the name of the fruit, and the amount of it. If the fruit is not registered in the dictionary, it would add the fruit and it's value to the dictionary. If the fruit is registered, it would check if its value is bigger than the original value in the dictionary. If it's bigger, it will replace the amount, but if the typed amount is smaller than the original amount, it wouldn't do anything.
I used the code below for checking for the average of the fruits. So it counts how many fruits I have bought and it accumulates it. So that later on, I can use it to find out the average by dividing the number by how many times I have accumulated it.
items[fruit_t]["av"]+=(fruit_n)
Here is question. When ever i try to add things to dictionary, it prints for first time, but when I move on to add another fruit, previously added fruit disappears. I don't get what is wrong. Also, I want to use .append instead of += as shown above, but when ever I try to do that, there's an error. I want to use append because later on, I can use len() to count how many numbers are in av
, sum up the av and divide by the len() value of av.
import pickle
def fruit():
with open('fruits.pickle', 'a') as f:
try:
items = pickle.load(f)
except ValueError:
items = {"Apple":{"av":10,"count":10},"Banana":{"av":14,"count":14},"Orange":{"av":23,"count":23},"Watermelon":{"av":54,"count":54}}
fruit_t = input("Please type in the name of the fruit: ")
fruit_n = int(input("Please type in the amount of the fruit: "))
if fruit_t in items:
items[fruit_t]["av"]+=(fruit_n)
if items[fruit_t]["count"] < fruit_n:
items[fruit_t]["count"] = fruit_n
else:
items[fruit_t] = {"av":fruit_n,"count":fruit_n}
with open('fruits.pickle', 'wb') as f:
pickle.dump(items, f)
for k in items:
print("{} monthly {}".format(k,items[k]["av"]))
print("{} total {}".format(k,items[k]["count"]))
fruit()
fruit()
Edited and working code.
import pickle
def fruit():
with open('fruits.pickle', 'rb') as f:
try:
items = pickle.load(f)
except ValueError:
items = {}
fruit_t = input("Please type in the name of the fruit: ")
fruit_n = int(input("Please type in the amount of the fruit: "))
if fruit_t in items:
items[fruit_t]["total"]+=(fruit_n)
if items[fruit_t]["count"] < fruit_n:
items[fruit_t]["count"] = fruit_n
else:
items[fruit_t] = {"total":fruit_n,"count":fruit_n}
with open('fruits.pickle', 'wb') as f:
pickle.dump(items, f)
for k in items:
print("{} monthly {}".format(k,items[k]["total"]))
print(items[k]["count"])
fruit()
fruit()

I'll answer your question with a very different approach:
pickle will not load your pickled file because you are opening the file in 'appending'-mode in line 3.
You are not noticing the error as you have enclosed the loading in a try-statement. Instead, the exception is caught and your items are loaded from default.
Solution: Change mode in open in line 3 to rb.

Given that you are not correcting the code in the question, here is what is wrong:
You have specified 'appending' as the mode in open on line 3.
This is not useful when you intend to read the file; instead use
r for reading, perhaps rb for reading a binary file.
Dedent line 8 (fruit_t = ...) as this marks the exit from the context manager starting on line 3 (with ... is a context manager). This will close the file again, as you are done reading it. Dedent following lines.
You do not need to keep track of each "purchase"; you can instead rely on 1) the sum of purchases and 2) the count of purchases. Calculating the average is very easy then. You can therefore split your dictionary into two.
On line 12, your logic eludes me and it contradicts what you write in your question.
Code example 1
from collections import Counter
fruits = {'apple':0, 'banana':0}
purchases = Counter(fruits)
fruits = Counter(fruits)
## on purchase
fr = 'apple'
buy = 4
fruits[fr] += 4
purchases[fr] += 1
See what happens if you buy a fruit that is not yet present in the Counters (i.e. set fr = 'mandarin').

Related

How do I manipulate data in a list that has been read in from a file using Python 2.x?

I am trying to create a program that will tally the cost of ingredients within a recipe and return a total cost for said recipe. I am teaching myself Python and have set this as a personal, but practical, challenge. However, I have hit a wall. Hard.
My idea was to read a file into a list. Multiply the ingredient within the list by the comma separated numeral. Add it all together, and return a single float for the overall cost.
#Phase 1 - MASTER INGREDIENTS LIST
flour_5lb = 2.5
sugar_4lb = 2.0
butter_lb = 3.0
eggs_doz = 3.0
#PHASE 2 - COST PER UNIT CONVERSION
flour_cup = flour_5lb*(1.0/20)
sugar_cup = sugar_4lb*(1.0/8)
butter_Tbsp = butter_lb*(1.0/32)
eggs_each = eggs_doz*(1.0/12)
#PHASE THREE - RECIPE ASSESSMENT
def main():
fileObject = open("filname.txt", "r")
fileLines = fileObject.readlines()
fileObject.close()
for line in fileLines:
print line
print "\n"
if __name__ == "__main__":
main()
The for line in fileLines: statement prints the following:
flour_cup, .5
milk_cup, .4
eggs_each, 3
butter_Tbsp, 3
Press any key to continue . . .
If I understand you correctly, you have to parse your file.
For this you need to know the format in which the ingredients are being stored. Since this program is for your personal use you may just choose the most simple.
So let's assume you have your ingredients in CSV format:
sugar 10g
flour 20g
...
Then you can use pythons buildin function split and iteration to obtain a list of list [['sugar', '10g'], ['flour', '10g'], ...].
Getting the amounts into python floats is a little tricky, since we haave to concern ourselves with the units.
Again - choose a fixed set of units to make your life a little easier.
Then use the in statement or the builtin function which checks if a given string has a certain suffix. (I will leave it to you to find this function.)
Then the hard part is done. Hope I could help without giving too much away.
Part of your difficulty is knowing how to split your input on the comma -- use split(). Another problem is converting the string to a float -- use float().
Your last problem is mapping input strings to values. You could write a function that maps strings to costs:
if item == "milk_cup":
return milk_cup
if item == "flour_cup":
return flour_cup
...
...but the better way (DRY) to do it is to use a dictionary.
In my sample below I've used dict() to make the dictionary as then I don't have to quote every string.
Here's a sample:
#!/usr/bin/python
pricelist = dict(
flour_cup=1.0,
milk_cup=0.4,
)
input = ["flour_cup, 0.5", "milk_cup, 0.4"]
total = 0
for line in input:
item, qty = line.split(",")
item = item.strip()
qty = float(qty)
if item in pricelist:
cost = qty * pricelist[item]
print "%s: %.02f\n" % (item, cost)
total += cost
else:
print "I don't know what '%s' is" % item
print "Total: %.02f" % total

saving last results in a text file

the problem i have is that i have a quiz which the user can pick from 3 classes. they then proceed to complete the quiz and currently their name and score is saved into a text file for the correct class (there are 3 different files for the 3 different classes). but how do i make it so if the same user has completed the quiz that only the last 2 scores that the student obtained is saved in the file rather than all of the scores.
if classChoice ==1:
File=open("A.txt","a+")
File.write(names+","+str(score)+"\n")
File.close()
if classChoice ==2:
File=open("B.txt","a+")
File.write(names+","+str(score)+"\n")
File.close()
if classChoice ==3:
File=open("C.txt","a+")
File.write(names+","+str(score)+"\n")
File.close()
Clearly you want to save your data in a specific data structure defined by yours. In your case you are interested in saving only last two scores of a specific student.
Let's observe how does your file "A.txt" look:
John,90
Sam,80
Alice,100
Sam,90
John,100
Instead of appending text each time, you have to read the whole file first, and convert it to something you can work with like dictionary.
def convert_file_to_dict(path):
d = {}
lines = open(path).splitlines()
for line in lines:
name, grade = line.split(',')
if name in d:
d[name].append(grade)
else:
d[name] = [grade]
return grade
In our case if I'll call convert_file_to_dict('A.txt'), I will receive dictionary which consists of { 'John':['90','100'], 'Sam':['80','90'], 'Alice':['100'] }. Notice that the order in the list of grades is preserved by order of lines in "A.txt".
Now with that dictionary you can control that only last 2 grades are kept:
def insert_new_grade(grades_dict, name, grade):
if name in grades_dict:
if len(grades_dict[name]) == 1:
grades_dict[name].append(str(grade))
else:
grades_dict[name] = grades_dict[name][1:] + [str(grade)]
else:
grades_dict[name] = [str(grade)]
Now all you need is to write a function which converts this dict to a file...
* You might want to use helpful objects like collections.defaultdict, but I didn't want to overkill here...

How do I save data in a text file python

So I am making a simple randomized number game, and I want to save the players High Score even after the program is shut down and ran again. I want the computer to be able to ask the player their name, search through the database of names in a text file, and pull up their high score. Then if their name is not there, create a name in the database. I am unsure on how to do that. I am a noob programmer and this is my second program. Any help would be appreciated.
Here is the Code for the random number game:
import random
import time
def getscore():
score = 0
return score
print(score)
def main(score):
number = random.randrange(1,5+1)
print("Your score is %s") %(score)
print("Please enter a number between 1 and 5")
user_number = int(raw_input(""))
if user_number == number:
print("Congrats!")
time.sleep(1)
print("Your number was %d, the computers number was also %d!") %(user_number,number)
score = score + 10
main(score)
elif user_number != number:
print("Sorry")
time.sleep(1)
print("Your number was %d, but the computers was %d.") %(user_number, number)
time.sleep(2)
print("Your total score was %d") %(score)
time.sleep(2)
getscore()
score = getscore()
main(score)
main(score)
EDIT:
I am trying this and it seems to be working, except, when I try to replace the string with a variable, it gives an error:
def writehs():
name = raw_input("Please enter your name")
a = open('scores.txt', 'w')
a.write(name: 05)
a.close()
def readhs():
f = open("test.txt", "r")
writehs()
readhs()
with open('out.txt', 'w') as output:
output.write(getscore())
Using with like this is the preferred way to work with files because it automatically handles file closure, even through exceptions.
Also, remember to fix your getscore() method so it doesn't always return 0. If you want it to print the score as well, put the print statement before the return.
In order to write a file using python do the following:
file2write=open("filename",'w')
file2write.write("here goes the data")
file2write.close()
If you want to read or append the file just change 'w' for 'r' or 'a' respectively
First of all you should ask your question clearly enough for others to understand.To add a text into text file you could always use the open built-in function.Do it like this.
>>> a = open('test.txt', 'w')
>>> a.write('theunixdisaster\t 05')
>>> a.close()
Thats all.If need further help try this website.
http://www.afterhoursprogramming.com/tutorial/Python/Writing-to-Files/
You could also use a for loop for the game to print all the scores.
Try this one on your own.It would rather be fun.
THE RECOMENDED WAY
Well as if the recommended way use it like this:
>>> with open('test.txt', 'w') as a:
a.write('theunixdisaster\t 05')
With this its certain that the file would close.
With variables
>>> name = sempron
>>> with open('test.txt', 'w') as a:
a.write('%s: 05' % name)
Now try calling it.Well I use python 3.4.2.So, if you get into errors, try to check if there is any difference in the string formatting with the python version that you use.

change/writing single value to csv file python

There is an error in my code :
_csv.Error: sequence expected
which i believe is because i am trying to write only one value not a list etc.
exRtFile = open ('exchangeRate.csv')
exchReader = csv.reader(exRtFile)
exchWriter = csv.writer(exRtFile)
loop2=0
while loop2==0:
selected=int(input("Please select an option: "))
if selected == 1:
change = input("What rate would you like to change: ")
changeRt = float(input("What would you like to change the rate to: "))
for row in exchReader:
currency = row[0]
if currency == change:
crntRt = row[1]
crntRt = changeRt
exchWriter.writerow(crntRt)
exRtFile.close()
what would be the best way to fix this, or is there a better wayy to change a value in an CSV file?
csv file:
Pound Sterling,1
Euro,1.22
US Dollar,1.67
Japanese Yen,169.948
Here is some code, not tested, that will do what you want. The idea is to read the text into memory, apply the updates, then write out the results over the original file.
You can further enhance this ask the user if they want to save their changes, and to add new currencies instead of just telling the user they're not known.
In the real world, I would break this code into three separate functions (or even classes), one for reading, one for writing, and one for editing the list.
import csv
rates = {}
# read file into dictionary
with open('csv_file.csv', 'r') as in_file:
rdr = csv.reader(in_file)
for item in reader:
rates[row[0]] = row[1]
# ask user for updates and apply to dictionary
while true:
cmd = raw_input('Enter exchange rate to adjust, or blank to exit')
if cmd is None or cmd.strip() == '':
break
if rates.has_key(cmd):
new_rate = float(raw_input('Enter new exchange rate:'))
rates[cmd] = new_rate
else:
print 'Currency {} is not known.'.format(cmd)
# Write the updated dictionary back over the same file.
with open('csv_file.csv', 'w') as out_file:
wrtr = csv_writer(out_file)
wrtr.writerows(rates)
Answering your question: Yes, the problem is that you were trying to write only a value, while writerow expects a list.
That said... Would you consider changing a bit the way your code works?
Here's what I've done (I've tested it now, so I know it works):
First, ask the user for all the changes to make and keep them in a dict where keys are the currency names (Euro, for instance) and the value is the new currency value (5.0, for instance) The user can get out of the loop pressing 0
Second, open and read your exchangeRate.csv file row by row. If the row[0] (name of the currency) is among the values to change, then change it in that row.
No matter what happens (regardless of whether the row needed to be changed or not) write that row in a new temporary file exchangeRate.csv.tmp
When all the rows in the original file are read, you'll have exchangeRate.csv.tmp with some rows unchanged and some rows changed. Swap (move) the .tmp file to exchangeRate.csv
Dunno... might be too much change maybe? Here it is, anyway:
import csv
import shutil
change_rates = {}
selected = 1
while selected:
selected=int(raw_input("Please select an option: (1 to change, 0 to exit)"))
if selected == 1:
change = raw_input("What rate would you like to change?: ")
changeRt = float(raw_input("What would you like to change the rate to: "))
change_rates[change] = changeRt
if len(change_rates) > 0:
with open('exchangeRate.csv', 'r') as f_in,\
open('exchangeRate.csv.tmp', 'w') as f_out:
exchReader = csv.reader(f_in)
exchWriter = csv.writer(f_out)
for row in exchReader:
if row[0] in change_rates:
row[1] = change_rates[row[0]]
exchWriter.writerow(row)
shutil.move('exchangeRate.csv.tmp', 'exchangeRate.csv')
And a sample execution below:
Please select an option: (1 to change, 0 to exit)1
What rate would you like to change?: Euro
What would you like to change the rate to: 5
Please select an option: (1 to change, 0 to exit)0
borrajax#borrajax:~/Documents/Tests$ cat ./exchangeRate.csv
Pound Sterling,1
Euro,5.0
US Dollar,1.67
Japanese Yen,169.948
You can always make more optimizations, such as... allow case insensitive searches, or check that the currency has actually been changed (like even if the user says he wants to change the currency Euro to 5.0, if that was the Euro's exchange rate then don't do anything)... Things like that.
EDIT 1:
I've just seen Larry Lustig's answer and I agree that for small files as it seems to be your case (files that you can fully load in memory) the continuous reading and writing from disk I posted is not optimal. His idea of keeping everything in memory and then do a bulk write to the same exchangeRate.csv file probably is a better fit for your needs.
EDIT 2:
To answer your questions in a comment to this answer:
what does .tmp do at the end of: exchangeRate.csv.tmp:
It's just a new name. I add the suffix .tmp to avoid a naming conflict with your original file (exchangeRate.csv). You could name it whatever you want, though (even foobar.baz)
What is the purpose of 'change' in the variable: change_rates[change] = changeRt:
change is a variable that contains the name of the currency to change (in the usage example I posted, change contains the string "Euro", because that's what the user (erm... me) typed on the console. Is just a way of accessing a dict.
What is the prupose of '[row[0]]' in: row1=change_rates[row[0]].
We agreed that when reading the file, row[0] (just like that, not [row[0]]) contains the name of the currency in the file (Euro, Pound Sterling... etcetera) right? So at a certain point of the execution row[0] will contain the string "Euro", which (in my test example) is the currency the user wanted to change. That string ("Euro") is also a key in the change_rates dictionary (because the user said he wanted to change it) so you are querying the value for the item with key "Euro" in the change_rates dictionary (which will give you 5.0). Is pretty much doing change_rates["Euro"] To see it a bit more clearer add the line print "Currencies to change: %s" % change_rates on the line right above if len(change_rates) > 0: (that'll show you how the dictionary looks like)
what does shutil.move('exchangeRate.csv.tmp', 'exchangeRate.csv') do?
It copies the file with the new currencies to exchangeRate.csv (see the shutil documentation)

'Splitting' List into several Arrays

I'm trying to complete a Project that will show total annual sales from an specific list contained in a .txt file.
The list is formatted this way:
-lastname, firstname (string)
-45.7 (float)
-456.4 (float)
-345.5 (float)
-lastname2, firstname2 (string)
-3354.7 (float)
-54.6 (float)
-56.2 (float)
-lastname3, firstname3 (string)
-76.6 (float)
-34.2 (float)
-48.2 (float)
And so on.... Actually, 7 different "employees" followed by 12 set of "numbers" (months of the year)....but that example should suffice to give an idea of what I'm trying to do.
I need to output this specific information of every "employee"
-Name of employee
-Total Sum (sum of the 12 numbers in the list)
So my logic is taking me to this conclusion, but I don't know where to start:
Create 7 different arrays to store each "employee" data.
With this logic, I need to split the main list into independent arrays so I can work with them.
How can this be achieved? And also, if I don't have a predefined number of employees (but a defined format :: "Name" followed by 12 months of numbers)...how can I achieve this?
I'm sure I can figure once I get an idea how to "split" a list in different sections -- Every 13 lines?
Yes, at every thirteenth line you'd have the information of an employee.
However, instead of using twelve different lists, you can use a dictionary of lists, so that you wouldn't have to worry about the number of employees.
And you can either use a parameter on the number of lines directed to each employee.
You could do the following:
infile = open("file.txt", "rt")
employee = dict()
name = infile.readline().strip()
while name:
employee[name] = list()
for i in xrange(1, 12):
val = float(infile.readline().strip())
employee[name].append(val)
name = infile.readline().strip()
Some ways to access dictionary entries:
for name, months in employee.items():
print name
print months
for name in employee.keys():
print name
print employee[name]
for months in employee.values():
print months
for name, months in (employee.keys(), employee.values()):
print name
print months
The entire process goes as follows:
infile = open("file.txt", "rt")
employee = dict()
name = infile.readline().strip()
while name:
val = 0.0
for i in xrange(1, 12):
val += float(infile.readline().strip())
employee[name] = val
print ">>> Employee:", name, " -- salary:", str(employee[name])
name = infile.readline().strip()
Sorry for being round the bush, somehow (:
Here is option.
Not good, but still brute option.
summed = 0
with open("file.txt", "rt") as f:
print f.readline() # We print first line (first man)
for line in f:
# then we suppose every line is float.
try:
# convert to float
value = float(line.strip())
# add to sum
summed += value
# If it does not convert, then it is next person
except ValueError:
# print sum for previous person
print summed
# print new name
print line
# reset sum
summed = 0
# on end of file there is no errors, so we print lst result
print summed
since you need more flexibility, there is another option:
data = {} # dict: list of all values for person by person name
with open("file.txt", "rt") as f:
data_key = f.readline() # We remember first line (first man)
data[data_key] = [] # empty list of values
for line in f:
# then we suppose every line is float.
try:
# convert to float
value = float(line.strip())
# add to data
data[data_key].append(value)
# If it does not convert, then it is next person
except ValueError:
# next person's name
data_key = line
# new list
data[data_key] = []
Q: let's say that I want to print a '2% bonus' to employees that made more than 7000 in total sales (12 months)
for employee, stats in data.iteritems():
if sum(stats) > 7000:
print employee + " done 7000 in total sales! need 2% bonus"
I would not create 7 different arrays. I would create some sort of data structure to hold all the relevant information for one employee in one data type (this is python, but surely you can create data structures in python as well).
Then, as you process the data for each employee, all you have to do is iterate over one array of employee data elements. That way, it's much easier to keep track of the indices of the data (or maybe even eliminates the need to!).
This is especially helpful if you want to sort the data somehow. That way, you'd only have to sort one array instead of 7.

Categories