Related
I'm tasked to create a function that takes a string filename as an argument, reads the file with the name filename, and prints
all confirmed reservations in order of the time.
A line in the file is formatted like so
name, time, reservation_status (can either be confirmed or canceled in uppercase)
An example of a file "reservations.txt" could look like this:
Alex, 20, CONFIRMED
Thomas, 16, CANCELLED
William, 18, CONFIRMED
The correct output when calling the function on this example file should look like this:
show_reservations("reservations.txt")
>>> William, 18
Alex, 20
My solution:
def show_reservations(filename):
with open(filename) as f:
for line in f.readlines():
line = line.replace(',', '').split()
status = line[2]
if status == "CONFIRMED":
name = line[0]
time = line[1]
print(name + ",", time)
However, calling my solution on the example file above gives me following output:
show_reservations("reservations.txt")
>>> Alex, 20
William, 18
What to do?
you don't store your data and you also need some sorting
def funct(e):
return e['time']
def show_reservations(filename):
with open(filename) as f:
l=[]
for line in f.readlines():
line = line.replace(',', '').split()
dict={}
status = line[2]
if status == "CONFIRMED":
dict["name"] = line[0]
dict["time"] = line[1]
name = line[0]
time = line[1]
l.append(dict)
l.sort(key=funct)
for i in l:
print('{0} , {1}'.format(i["name"],i["time"]))
show_reservations("input.txt")
It happens because your original sequence comes in this way:
Alex, 20, CONFIRMED
...
William, 18, CONFIRMED
So you can save your filtered elements into a list and apply sorting on it. For example using sorted function.
You could try something like this:
def show_reservations(filename):
confirmed_orders = []
with open(filename) as f:
for line in f.readlines():
line = line.replace(',', '').split()
name, _time, status = line
if status == "CONFIRMED":
confirmed_orders.append((name, _time))
confirmed_orders_by_time = sorted(confirmed_orders, key=lambda x: x[1])
for name, _time in confirmed_orders_by_time:
print(name + ",", _time)
Also several additional suggestions in case the snippet you've provided is a real production code:
time is a bad name for variable because it can clash with built-in Python's module time.
split gives you tuple, so instead of messing with accessing by index you can unpack it:
name, _time, status = line
This thing line.replace(',', '').split() won't work correctly if name or status in the file will have a "space". Consider to use csv or something else for parsing data file.
If you use Python 3.5 or higher f-string is a preferable way instead of manual string concatenation:
print(f"{name}, {_time}")
def show_reservations(filename):
reservations = []
with open(filename) as f:
for line in f.readlines():
splitted_line = line.replace(',', '').split()
status = splitted_line[2]
if status == "CONFIRMED":
time = splitted_line[1]
name = splitted_line[0]
reservations.append({"time":time, "name":name})
return sorted(reservations, key=lambda k: k['time'])
for reservation in show_reservations("reservations.txt"):
print(reservation["name"] + ",", reservation["time"])
Instead of directly printing, append the entries to a list of tuples (time, name). Then after the list, sort it (li.sort()), and loop through it again, this time printing.
def editselection():
#this converts the text in the files into a list in a list
with open("stocks", "r") as stocks:
for line in stocks:
stripped_line = line.strip()
line_list = stripped_line.split()
list_of_items.append(line_list)
itemselection = input('Choice: ')
if itemselection.isalpha() == True:
ManageStock()
elif itemselection == '':
ManageStock()
itemselection = int(itemselection)
os.system('clear')
#the square brackets are the indexes so for example if they select 0, the first item turned into a list would be known as specific item
specificitem = list_of_items[itemselection]
changeitem(specificitem)
return specificitem
I'm trying to call the variable 'specificitem' to the function AddItem()
def AddToCart(specificitem):
os.system('clear')
number = 0
os.system('clear')
print ("""Here is the current stock
--------------------------
Name, Price, Quantity
--------------------------
""")
with open ('stocks', 'r') as stocks:
for i in stocks:
number = str(number)
print (number+'.' , i)
number = int(number)
number = number + 1
#this converts the text in the files into a list in a list
with open("stocks", "r") as stocks:
for line in stocks:
stripped_line = line.strip()
line_list = stripped_line.split()
list_of_items.append(line_list)
itemselection = input('Choice: ')
if itemselection.isalpha() == True:
AddToCart()
if itemselection == '':
MakeASale()
itemselection = int(itemselection)
#the square brackets are the indexes so for example if they select 0, the first item turned into a list would be known as specific item
quantity = input('How many would you like? ')
chosenitem2 = list_of_items[itemselection]
with open ('cart' , 'a') as cart:
chosenitem2 = str(chosenitem2)
cart.write(chosenitem2 + '\n')
with open("cart", "r") as cart:
for line in cart:
stripped_line = line.strip()
line_list = stripped_line.split()
list_of_cart.append(line_list)
with open ("cart" , "r+") as cart:
data = cart.read()
data = data.replace(chosenitem2[2], quantity)
cart.close
cart = open('cart' , 'wt')
cart.write(data)
cart.close()
with open ("stocks" , "r+") as stocks:
data = stocks.read()
data = data.replace(specificitem[2], chosenitem2[2])
stocks.close
stocks = open('stocks' , 'wt')
stocks.write(data)
stocks.close()
print(chosenitem2)
though it comes up with AddToCart() missing 1 required positional argument: 'specificitem'
I'm trying to use the variable from editselection to edit the quantity for example when the user enters a value it adds it to the file cart and 'subtracts' if you will from the file stocks, the use of global is unavailable due to the fact that I'll just get marked down. I've been stuck on this for 2 days now
In the first function write (function name)editselection.(variable name)specificitem=(value)list_of_items[itemselection]
And on the second function call the variable for example like this:
print(editselection.specificitem)
And this will print the value of the variable.
This is called a function variable (or something like this)
I want to add a new column and new values to it. I'm just using normal file handling to do it (just adding a delimiter). I actually did try using csv but the csv file would have one letter per cell after running the code.
#import csv
#import sys
#csv.field_size_limit(sys.maxsize)
inp = open("city2", "r")
inp2 = open("op", "r")
oup = open("op_mod.csv", "a+")
#alldata = []
count = 0
for line in inp2:
check = 0
if count == 0:
count = count + 1
colline = line + "\t" + "cities"
oup.write(colline)
continue
for city in inp:
if city in line:
print(city, line)
linemod = line + "\t" + city #adding new value to an existing row
#alldata.append(linemod)
oup.write(linemod) #writing the new value
check = 1
break
if check == 0:
check = 1
#oup.write(line)
#alldata.append(line)
inp.close()
inp = open("city2", "r")
#writer.writerows(alldata)
inp.close()
inp2.close()
oup.close()
Expected result:
existing fields/values ... new field/value
actual result:
existing fields/values ... new line
new field/value ...next line
there is a carriage return at the end of line, you can remove it using line.rstrip() similar to this answer:
Deleting carriage returns caused by line reading
Hey everyone just have an issue with a text file and putting it into a dictionary.
So my code first starts off by gathering data from a website and writes it to a text file. From there I reopen the file and make it into a dictionary to transfer the data from the text to the dictionary. In the while loop, I am getting the error of
key,value = line.split()
ValueError: too many values to unpack (expected 2)
Which I'm not sure why if I'm using the wrong method to write the text file data to the new place in the program of "countryName"
def main():
import requests
webFile = "https://www.cia.gov/library/publications/the-world-factbook/rankorder/rawdata_2004.txt"
data = requests.get(webFile) #connects to the file and gest a response object
with open("capital.txt",'wb') as f:
f.write(data.content) #write the data out to a file – wb used since thecontent from the response object is returned as abinary object.
f.close()
infile = open('capital.txt', 'r')
line = infile.readline()
countryName = {}
while line != "":
key,value = line.split()
countryName[key] = value
line = infile.readline()
infile.close()
userInput = input("Enter a country name: ")
for i in countryName:
while(userInput != 'stop'):
print("The per capita income in",countryName[key], "is",countryName[value])
userInput = input("Enter a country name: ")
main()
while line != "":
key,value = line.split()
countryName[key] = value
line = infile.readline()
infile.close()
This is where my issue pops up.
I am trying to have the text file information be put into a dictionary.
Once done I want to iterate through the dictionary, and have the user enter a country name. Then in response, the program finds the country name and returns the name of the country and the capital income as well.
So if "United States" is inputed the output would be "The per capita income in the United States is $54000" That as an example to show what im doing.
The key being the country name and the value being the income.
countryName = {}
with open('capital.txt','r') as infile:
for line in infile:
num,key,value = line.split()
countryName[key] = value
num,key,value = infile.readline().split()
#print(line)
print(countryName)
The issue is that the lines return three values each: The line number, the country, and the per-capita income:
fh.readline().split()
['2', 'Qatar', '$124,500']
To fix that, you can capture that third value in a throwaway variable:
n, key, val = fh.readline().split()
However, there's a different problem, what if your country name has spaces in it?
['190', 'Micronesia,', 'Federated', 'States', 'of', '$3,400']
You can use the *arg syntax to capture any number of arguments in a variable:
myline = ['190', 'Micronesia,', 'Federated', 'States', 'of', '$3,400']
num, *key, value = myline
# key is now ['Micronesia,', 'Federated', 'States', 'of']
You can then use join to create a single string
key = ' '.join(key)
# 'Micronesia, Federated States of'
Furthermore, it's important to keep your conventions consistent in your program. You use the with context handler to open and close an earlier file, that's a good practice, so keep it with the other file as well. Also, you can iterate over the file-handle directly like so:
with open('capital.txt', 'r') as infile:
for line in infile: # no need to check the line contents or call readline
num, *key, value = line.split()
key = ' '.join(key)
# No need to close your file at the end either
Last, your print statement will raise a KeyError:
print("The per capita income in",countryName[key], "is",countryName[value])
You've already stored value at countryName[key], so the lookup is only against key, rather than value:
# key is already a string representing the country name
# countrName[key] is the value associated with that key
print("The per capita income in", key , "is", countryName[key])
I have a stock file in the format of this:
12345678,Fridge,1,50
23456789,Car,2,50
34567890,TV,20,50
This is the code:
def main():
products = {}
#This is the file directory being made.
f = open('stockfile.txt')
#This is my file being opened.
for line in f:
# Need to strip to eliminate end of line character
line = line[:-1]
#This gets rid of the character which shows and end of line '\n'
row = line.split(',')
#The row is split by the comma
products[row[0]] = [row[1], row[2],row[3]]
#The products are equal to row 1 and row 2 and row 3. The GTIN is going to take the values of the product and price so GTIN 12345678 is going to correspond to Fridge and 1.
print(products)
total = 0
print('Id Description Total')
while True:
GTIN = input('Please input GTIN ')
if(GTIN not in products):
print('Sorry your code was invalid, try again:')
break
row = products[GTIN]
print(GTIN)
description = row[0]
value = row[1]
stock = row[2]
print(stock)
quantity = input('Please also input your quantity required: ')
row[2]= int(stock) - int(quantity)
products[row[2]] = row[2]
product_total= (int(quantity)*int(value))
New_Stock = GTIN + ',' + description + ',' + value + ',' + str(products[row[2]])
f = open('stockfile.txt','r')
lines = f.readlines()
f.close()
f = open("stockfile.txt","a")
for row in lines:
if((row + '\n') != (New_Stock + '\n')):
f.write(New_Stock)
f.close()
print('%20s%20s%20s' % (GTIN, description, product_total))
total = total + product_total
print('Total of the order is £%s' % total)
print(products)
main()
However, the code doesn't update the stock's. What it should do is get rid of the previous stock for the product given and then update it according to the quantity the user has just bought.
I haven't got to it yet but once the stock hits zero I need my code to then tell the user that we have run out of stock and need some new stock. Then there needs to be a message to the user to wait until we restock and then display the price of restocking as well.
If you have time please could you make this new bit of code as well but if not could you just explain how to update the stock and why my code isn't working, thank you.
When you seek to a given line and call write, in order to completely overwrite that line, without affecting other lines or inadvertently creating new lines, each line in your stock must have a fixed width. How do you ensure fixed width? By giving each field in the record a fixed width. Basically, you choose a maximum number of characters each field can have; here I'll assume 8 for all fields (though they must not all be the same), so your stock will be stored this way:
12344848, Fridge, 2, 50
13738389, TV, 5, 70
If you keep going this way, each line will have a maximum width which will enable you to seek to the start of the line and overwrite it completely. Try this code:
MAX_FIELD_LEN = 8
def main():
products = {}
product_location = {}
location = 0
# This is the file directory being made.
with open('stockfile.txt', 'r+') as f:
# This is my file being opened.
for line in f:
# keep track of each products location in file to overwrite with New_Stock
product_location[line.split(',')[0]] = location
location += len(line)
# Need to strip to eliminate end of line character
line = line[:-1]
# This gets rid of the character which shows and end of line '\n'
row = line.split(',')
# The row is split by the comma
products[row[0]] = [row[1], row[2], row[3]]
# The products are equal to row 1 and row 2 and row 3. The GTIN is going to take the values of the product and price so GTIN 12345678 is going to correspond to Fridge and 1.
print(products)
total = 0
while True:
GTIN = input('Please input GTIN: ')
# To terminate user input, they just need to press ENTER
if GTIN == "":
break
if (GTIN not in products):
print('Sorry your code was invalid, try again:')
break
row = products[GTIN]
description, value, stock = row
print('Stock data: ')
print('GTIN \t\tDesc. \t\tStock \t\tValue')
print(GTIN,'\t',description,'\t', stock, '\t', value)
quantity = input('Please also input your quantity required: ')
row[2] = str(int(stock) - int(quantity))
product_total = int(quantity) * int(value)
for i in range(len(row)):
row[i] = row[i].rjust(MAX_FIELD_LEN)
New_Stock = GTIN.rjust(MAX_FIELD_LEN) + ',' + ','.join(row) + '\n'
#print(New_Stock, len(New_Stock))
f.seek(product_location[GTIN])
f.write(New_Stock)
print('You bought: {0} {1} \nCost: {2}'.format(GTIN, description, product_total))
total = total + product_total
f.close()
print('Total of the order is £%s' % total)
main()
Ensure that each field in the TXT file is exactly 8 characters wide (not including the commas) when using this program. If you want to increase the field width, change the MAX_FIELD_LEN variable accordingly. Your TXT file should look like this:
In the first few lines you are loading the whole data file in memory :
for line in f:
products[row[0]] = [row[1], row[2],row[3]]
So then just update the data in memory, and have users enter a special command : "save" to write the whole list to your file.
You could also catch your application process KILL signal so if a user hits ctrl + c, you can ask him if he wants to save before quitting.
And maybe save a temporary copy of the list to a file every few seconds.
I suggest you use the shelve module for this, if your customers intend to run this program many times. Reading the whole file into memory and writing it anew as text will become inefficient as your stock grows. Shelve creates persistent files (3 files to be exact) on your PC for storing your data. Most importantly, shelve would give you the same dict interface you want, so that all you have to do is call shelve.open() on the file and you can begin accessing/updating your stock using GTINs as keys. Its very straightforward, just look at the python manuals. If you really want a text file, you could have your program, iterate through the shelve file containing your stock (same as for a dictionary) and write keys (GTIN) and their values (your stock quantity) to a text file you opened. This way, you have easy intuitive access to your records and also a readable format in your TXT file.
MAX_FIELD_LEN = 8
def main():
products = {}
product_location = {}
location = 0
# This is the file directory being made.
with open('stockfile.txt', 'r+') as f:
# This is my file being opened.
for line in f:
# keep track of each products location in file to overwrite with New_Stock
product_location[line.split(',')[0]] = location
location += len(line)
# Need to strip to eliminate end of line character
line = line[:-1]
# This gets rid of the character which shows and end of line '\n'
row = line.split(',')
# The row is split by the comma
products[row[0]] = [row[1], row[2], row[3]]
# The products are equal to row 1 and row 2 and row 3. The GTIN is going to take the values of the product and price so GTIN 12345678 is going to correspond to Fridge and 1.
print(products)
total = 0
while True:
GTIN = input('Please input GTIN: ')
# To terminate user input, they just need to press ENTER
if GTIN == "":
break
if (GTIN not in products):
print('Sorry your code was invalid, try again:')
break
row = products[GTIN]
description, value, stock = row
print('Stock data: ')
print('GTIN \t\tDesc. \t\tStock \t\tValue')
print(GTIN,'\t',description,'\t', stock, '\t', value)
quantity = input('Please also input your quantity required: ')
row[2] = str(int(stock) - int(quantity))
product_total = int(quantity) * int(value)
for i in range(len(row)):
row[i] = row[i].rjust(MAX_FIELD_LEN)
New_Stock = GTIN.rjust(MAX_FIELD_LEN) + ',' + ','.join(row) + '\n'
#print(New_Stock, len(New_Stock))
f.seek(product_location[GTIN])
f.write(New_Stock)
print('You bought: {0} {1} \nCost: {2}'.format(GTIN, description, product_total))
total = total + product_total
f.close()
print('Total of the order is £%s' % total)
main()
This was the text file:
12345678, Fridge, 1, 50
23456789, Car, 2, 50
34567890, TV, 20, 50
Does it make a difference I am doing this on a Mac desktop or that it is python 3.4.3?
The suggestion above using shelve sounds like a good idea, but if you want to keep your file as is but only update the records that are changed (instead of rewriting the whole file each time) using (most) of your code, this seems to work.
def main():
products = {}
product_location = {}
location = 0
# This is the file directory being made.
with open('stockfile.txt', 'r+') as f:
# This is my file being opened.
for line in f:
# keep track of each products location in file to overwrite with New_Stock
product_location[line.split(',')[0]] = location
location += len(line)
# Need to strip to eliminate end of line character
line = line[:-1]
# The row is split by the comma
row = line.split(',')
products[row[0]] = [row[1], row[2], row[3]]
"""
The products are equal to row 1 and row 2 and row 3. The GTIN is going to take the values of the product and
price so GTIN 12345678 is going to correspond to Fridge and 1.
"""
print(sorted(products.items()))
total = 0
while True:
GTIN = input('\nPlease input GTIN or press [Enter] to quit:\n')
# To terminate user input, they just need to press ENTER
if GTIN == "":
break
if (GTIN not in products):
# Let the user continue with order after mistake in GTIN input
print('Sorry your code was invalid, try again:')
continue
row = products[GTIN]
print('GTIN:', GTIN)
description = row[0]
value = row[1]
stock = row[2]
stock_length = len(row[2])
backorder = 0
print('In Stock:', stock)
quantity = input('Please also input your quantity required:\n')
if int(quantity) > int(stock):
row[2] = 0
backorder = int(quantity) - int(stock)
# TO DO
Backordered_Stock = GTIN + ',' + description + ',' + value + ',' + str(backorder) + '\n'
else:
row[2] = int(stock) - int(quantity)
products[row[2]] = row[2]
product_total = (int(quantity) * int(value))
New_Stock = GTIN + ',' + description + ',' + value + ',' + str(products[row[2]]).rjust(stock_length) + '\n'
f.seek(product_location[GTIN])
f.write(New_Stock)
print('Ordered - {0:>6} GTIN: {1:>10} Desc: {2:<20} at £{3:>6} Total value: £{4:>6} On backorder: {5:>4}'.
format(int(quantity), GTIN, description, int(value), product_total, backorder))
total = total + product_total
print('Total of the order is £%s' % total)
main()