Python - Write an array to csv / txt and then read - python

So if I have the following code:
database = []
Name = input("What's the members name?")
MT = input("What membership type?")
DOB = input("What is the member DOB?")
DJ = (now.day ,"/" , now.month, "/", now.year)
year1 = int(now.year)
month1 = int(now.month)
day1 = int(now.day)
ry = int(year1 + 1)
rm = month1
rd = day1
renewal = (day1, month1, year1 + 1)
details = ["Name:", Name, "Membership Type:", MT, "Date of Birth:", DOB, "Date Joined:", DJ,"Renewal Date:", renewal, "Renewal Year:", ry]
database.append(details)
menu()
How would I go about saving (database) to a text file / csv file to be read later.
I have tried pickle but the issue is I need to be able to get each part of the array seperate.
For example if I type:
print(database[1])
I will return all Names stored as "Name", however if I were to write the file using pickle when I bring it back in then
print (database[1])
now shows the entirety of the second user added. I need to be able to save (database) and have it in the same format when read back in.
Expected output using JSON or Pickle(assuming the first user inputted name as "Jeff" and second inputted name as "John")
print (database[1])
Jeff
John
Actual output:
["Name:", John, "Membership Type:", MT, "Date of Birth:", DOB, "Date Joined:", DJ,"Renewal Date:", renewal, "Renewal Year:", ry]
Sorry for the bad explanation I'm new to python.

It seems you are creating an array of records. Try accessing the data in this way:
print(database[0][1]) #[0] for the first record, [1] for second item
print(database[1][1]) #second user, second item

Related

How can I send a routine email using a list as input?

I'm trying to write code in Python to help with sending an email that I send about twice a week, with the same format every time and just a few elements that differ between emails, so I wrote the following code to help with this:
def visitor():
visitors = []
number_of = int(input("How many visitors are you signing in? "))
time = input("What time are they coming? ")
comments = """
Please type the name of the first visitor, and their nationality on the next line, the name of the second visitor
and their nationality on the next line, until you wrote down all the names and nationalities.
If you wanna stop the program and execute the code with the names & nationalities, just type quit
"""
print(comments)
name, i = "", 1
while name != "quit":
name = str(input("Ignore: "))
visitors.append(name)
visitors = visitors.pop(-1)
email = f"""
Hello,
I have {number_of} visitors coming today at {time}.
Name: {visitors[i]}
Nationality: {visitors[i + 1]}
"""
for i in range(len(visitors)):
to_add = f"""
Name: {visitors[i]}
Nationality: {visitors[i + 1]}
"""
email += to_add
ending = "Awaiting your approval\nThank you"
email += ending
return email
visitor()
However, upon running this code, I run into a problem in line 25, saying "Index out of range" ( line 25 is Nationality: {visitors[i + 1]} ). This normally shouldn't happen since the list has more than one element. Can someone help with this?
P.S. I have another, way longer code written for this that works, but I wanted to try and improve it by making it less sloppy.
The visitors list is acceeded at offset i+1, and i go up to len(visitors)-1 (upper limit specified for the loop through range()), so there is an access out of range when i = len(visitors) - 1

Python List Index Ouf Of Range In IF Statement

So i have multiple patients' information stored in database.txt and i want to retrieve the data from the file into a list.
And the system prompt for patient's id to search and display other information of the patient such as Name, Age, Group & Zone.
However, i'm getting error from line 12, but the similar syntax in line 17 is able to run without problem.
search_keyword = input() # Asks for patient's name or id (either one)
with open("database.txt", "r") as database:
for data in database:
for patients in data.split('|'):
patient_details = []
for details in patients.split(','):
patient_details.append(details)
print(patient_details) # test
print(len(patient_details) # test
print(patient_details.index('Patient001')) # test
print(patient_details[4]) # test
if search_keyword == patient_details[0] or search_keyword == patient_details[4]: # error occured here, where it says list index out of range.
print("Name: " + patient_details[0])
print("Age: " + patient_details[1])
print("Group: " + patient_details[2])
print("Zone: " + patient_details[3])
print("ID: " + patient_details[4]) # no error here, patient_details[4] is able to display patient's id
database.txt
John,18,A,1,Patient001|Nick,20,F,9,Patient002
Test command for line 8,9, 10 and 11:
Line 8: [John, 18, A, 1, Patient001]
Line 9: 5
Line 10: 4
Line 11: IndexError: list index out of range
Can someone explain why this is happening, and any solutions regarding this issue without using any imported modules? Thank you for any assistance.
Imo a very good use-case for a named tuple:
from collections import namedtuple
text = "John,18,A,1,Patient001|Nick,20,F,9,Patient002"
# build database
Patient = namedtuple('Patient', ['name', 'age', 'group', 'zone', 'id'])
db = [Patient(*patient) for entry in text.split("|") for patient in [entry.split(",")]]
# Asks for patient's id
search_keyword = input("Please give an ID: ")
# query the database
result = [patient for patient in db if patient.id == search_keyword]
# or patient.id.startswith(), etc.
print(result)
Without any imported modules, you could use
text = "John,18,A,1,Patient001|Nick,20,F,9,Patient002"
# build database
db = [entry.split(",") for entry in text.split("|")]
search_keyword = input("Please give an ID: ") # Asks for patient's id
# query the database
result = [patient for patient in db if patient[4] == search_keyword]
print(result)
I see no flaw in the code. Although, I can point out a few ways to optimise it :
patient_details = dict()
with open("database.txt", "r") as database:
for data in database:
for patients in data.split('|'):
patients = patients.split(',')
patient_details[patients[4]] = patients[0:4]
search_keyword = input() # Asks for patient's id
if patient_details.get(search_keyword, None):
patient_detail = patient_details[search_keyword]
print("Name: " + patient_detail[0])
print("Age: " + patient_detail[1])
print("Group: " + patient_detail[2])
print("Zone: " + patient_detail[3])
print("ID: " + search_keyword)
Using map instead of a linear search would allow you to search optimally.

How can I read from a file while differentiating the variables?

I just started studying Python and I have homework that I don't know how to begin with.
I have to read info about the employees of a company: name, age, occupation, salary, years_in_the company from a (txt) file. They are found on separate lines, and are split by a tab, for example:
Helen 20 Network Designer 5449 9
Jasmine 40 Software Architect 2536 1
Phoebe 28 Software Engineer 2627 7
Aysha 34 Software Developer 6441 3
Now, with this info I have to create a few functions like the average age of the employees, best-paid job, best-paid employee and so on. I do not know how to properly read the data from the file and how to implement the functions. I was thinking to define the functions at first, and then read all the data from the file, but a friend of mine told me that I could define each function and inside it I could read the necessary data.
For example, if I were to calculate the average age of the employees, I was thinking about doing it like this:
def avg(*args):
count = len(args)
if args > 0:
age_sum = 0
for i in args:
age_sum += i
return age_sum / count
else:
return 0
The problem is, I don't know how to fetch the proper data to the function. Can anyone please help me understand how to do it properly?
This is the one way, but there might best way than this to do that, but at least this will help you to deal with your problem. You can optimize the code plus you can change the variable from int to float for better coverage of avg etc and there should not be an empty line between lines in the file.
#print all detail
def print_all():
file = open("data.txt","r")
for line in file:
fields = line.split(" ")
print ("name "+ fields[0])
print ("age "+ fields[1])
print ("occupation "+ fields[2])
print ("type occupation "+ fields[3])
print ("salary "+ fields[4])
print ("years_in_the_company "+ fields[5])
file.close()
# avg salary
def avg__salary(employ = "salary" ):
file = open("data.txt","r")
avg=0
for salary in file:
salary_field = salary.split(" ")
avg=avg+int(salary_field[4])
file.close()
return avg
# avg age
def avg__age(employ = "age" ):
file = open("data.txt","r")
avg_age=0
for age in file:
age_field = age.split(" ")
avg_age=avg_age+int(age_field[1])
file.close()
return avg_age
# best paid job
def best_paid(employ = "paid" ):
file = open("data.txt","r")
bestpaid=0
for age in file:
age_field = age.split(" ")
if bestpaid < age_field[4]:
bestpaid=age_field[4]
file.close()
return bestpaid
number_of_lines=open('data.txt', 'r').read().count("\n")
print("All employ detail")
print_all()
print("Avg salary is",avg__salary()/number_of_lines)
print("Avg age is",avg__age()/number_of_lines)
print("Best paid is",best_paid())

Python - Replacing a specific value in a CSV file while keeping the rest

So I have a CSV file that looks something like this:
Username,Password,Name,DOB,Fav Artist,Fav Genre
Den1994,Denis1994,Denis,01/02/1994,Eminem,Pop
Joh1997,John1997,John,03/04/1997,Daft Punk,House
What I need to be able to do is let the user edit and change their Fav Artist and Fav Genre so that their new values are saved to the file in place of the old ones. I'm not the very advanced when it comes to CSV so I'm not sure where to begin with it, therefore any help and pointers will be greatly appreciated.
Thanks guys.
EDIT:
Adding the code I have so far so it doesn't seem like I'm just trying to get some easy way out of this, generally not sure what to do after this bit:
def editProfile():
username = globalUsername
file = open("users.csv", "r")
for line in file:
field = line.split(",")
storedUsername = field[0]
favArtist = field[4]
favGenre = field[5]
if username == storedUsername:
print("Your current favourite artist is:", favArtist,"\n" +
"Your current favourite genre is:",favGenre,"\n")
wantNewFavArtist = input("If you want to change your favourite artist type in Y, if not N: ")
wantNewFavGenre = input("If you want to change your favourite genre type in Y, if not N: ")
if wantNewFavArtist == "Y":
newFavArtist = input("Type in your new favourite artist: ")
if wantNewFavGenre == "Y":
newFavGenre = input("Type in your new favourite genre: ")
This is how it would look like using pandas
import pandas as pd
from io import StringIO
# Things you'll get from a user
globalUsername = "Den1994"
field = 'Fav Artist'
new_value = 'Linkin Park'
# Things you'll probably get from a data file
data = """
Username,Password,Name,DOB,Fav Artist,Fav Genre
Den1994,Denis1994,Denis,01/02/1994,Eminem,Pop
Joh1997,John1997,John,03/04/1997,Daft Punk,House
"""
# Load your data (e.g. from a CSV file)
df = pd.read_csv(StringIO(data)).set_index('Username')
print(df)
# Now change something
df.loc[globalUsername][field] = new_value
print(df)
Here df.loc[] allows you to access a row by the index. In this case Username is set as index. Then, [field] selects the column in that row.
Also, consider this:
df.loc[globalUsername][['Fav Artist', 'Fav Genre']] = 'Linkin Park', 'Nu Metal'
In case you have a my-data.csv file you can load it with:
df = pd.read_csv('my-data.csv')
The code above will return
Password Name DOB Fav Artist Fav Genre
Username
Den1994 Denis1994 Denis 01/02/1994 Eminem Pop
Joh1997 John1997 John 03/04/1997 Daft Punk House
and
Password Name DOB Fav Artist Fav Genre
Username
Den1994 Denis1994 Denis 01/02/1994 Linkin Park Pop
Joh1997 John1997 John 03/04/1997 Daft Punk House
Try this
import pandas as pd
data = pd.read_csv("old_file.csv")
data.loc[data.Username=='Den1994',['Fav Artist','Fav Genre']] = ['Beyonce','Hard rock']
data.to_csv('new_file.csv',index=False)
python has a built-in module dealing with csv, there are examples in the docs that will guide you right.
One way to do is to use the csv module to get the file you have into a list of lists, then you can edit the individual lists (rows) and just rewrite to disk what you have in memory.
Good luck.
PS: in the code that you have posted there is no assignment to the "csv in memory" based on the user-input
a minimal example without the file handling could be:
fake = 'abcdefghijkl'
csv = [list(fake[i:i+3]) for i in range(0, len(fake), 3)]
print(csv)
for row in csv:
if row[0] == 'd':
row[0] = 'changed'
print(csv)
the file handling is easy to get from the docs, and pandas dependance is avoided if that is on the wishlist

"Cannot deserialize instance of string from START_ARRAY value" Salesforce API issue

Trying to create a SF Contact with values from an .xlsx sheet.
I can create a contact if I manually type in a fake email address, lastname and firstname but cannot reference it to a value I have defined from an xlsx sheet.
the print commands are working fine and reading the appropriate data I want them to read.
Only been doing Python for 2 weeks now and have already been able to read, write and save data to/from MySQLdb without issue but now running into this issue and not finding much info on this specifically with SalesForce. Any help would be greatly appreciated.
So the full error is:
File "C:\Python27\lib\site-packages\simple_salesforce-0.70-py2.7.egg\simple_salesforce\api.py", line 749, in _exception_handler
raise exc_cls(result.url, result.status_code, name, response_content)
simple_salesforce.api.SalesforceMalformedRequest: Malformed request https://na48.salesforce.com/services/data/v37.0/sobjects/Contact/. Response content: [{u'errorCode': u'JSON_PARSER_ERROR', u'message': u'Cannot deserialize instance of string from START_ARRAY value [line:1, column:2]'}]
Email = sheet.col_values(1, 1)
Last = sheet.col_values(2, 1)
First = sheet.col_values(3, 1)
print Email
print Last
print First
sf.Contact.create({'LastName' : Last,'FirstName' : First,'Email' : Email})
Okay, Error is fixed but it only creates one contact/case on salesforce which is the last row in the xlsx sheet rather than creating a contact/case for each row in the xlsx. It reads everything for the most part correctly and does in fact create a contact the correct way but only the last row.
Current Code:
for c in range(sheet.ncols):
for r in range(sheet.nrows):
Email = sheet.col_values(1,r)[0]
print Email
Last = sheet.col_values(2,r)[0]
print Last
First = sheet.col_values(3,r)[0]
print First
Phone = sheet.col_values(4,r)[0]
print Phone
Street = sheet.col_values(5,r)[0]
print Street
City = sheet.col_values(6,r)[0]
print City
Postal = sheet.col_values(7,r)[0]
print Postal
Product = sheet.col_values(8,r)[0]
print Product
Store = sheet.col_values(9,r)[0]
print Store
SN = sheet.col_values(10,r)[0]
print SN
Name = sheet.col_values(3,r)[0]+sheet.col_values(2,r)[0]
sf.Contact.create({'FirstName' : First, 'LastName' : Last, 'Email' : Email, 'Phone' : Phone, 'MailingStreet' : Street, 'MailingCity' : City, 'MailingPostalCode' : Postal})
The error message from the server says
Cannot deserialize instance of string from START_ARRAY value [line:1,
column:2]
meaning that the server is expecting a field value to be a string, but the request has an array instead.
Therefore guessing that sheet.col_values() returns an array, you'd want to change it to
Email = sheet.col_values(1, 1)[0]
Last = sheet.col_values(2, 1)[0]
First = sheet.col_values(3, 1)[0]
Updated for 2nd issue:
Indents are significant in python, your create call only happens once because its outside the loop, you need to move it inside the loop, e.g.
for c in range(sheet.ncols):
for r in range(sheet.nrows):
Email = sheet.col_values(1,r)[0]
print Email
Last = sheet.col_values(2,r)[0]
print Last
First = sheet.col_values(3,r)[0]
print First
Phone = sheet.col_values(4,r)[0]
print Phone
Street = sheet.col_values(5,r)[0]
print Street
City = sheet.col_values(6,r)[0]
print City
Postal = sheet.col_values(7,r)[0]
print Postal
Product = sheet.col_values(8,r)[0]
print Product
Store = sheet.col_values(9,r)[0]
print Store
SN = sheet.col_values(10,r)[0]
print SN
Name = sheet.col_values(3,r)[0]+sheet.col_values(2,r)[0]
sf.Contact.create({'FirstName' : First, 'LastName' : Last, 'Email' : Email, 'Phone' : Phone, 'MailingStreet' : Street, 'MailingCity' : City, 'MailingPostalCode' : Postal})

Categories