How to print a dictionary made up of lines from a file in python3? - python-3.x

Any help is much appreciated! Thanks
I have a dictionary made up of lines extracted from a file like this:
Danny Shalev, 050-1111111, aaa#aaa.com
Gil Rom, 050-2222222, bbb#bbb.com
Tal Yakir, 050-3333333, ccc#ccc.com
Edit: my goal is for the dict to be printed out like this:
Danny Shalev - 050-1111111 - aaa#aaa.com
Gil Rom - 050-2222222 - bbb#bbb.com
Tal Yakir - 050-3333333 - ccc#ccc.com
The first name is the key, and the rest are the values.
I have written the code for converting the file lines into a dict, and I want to print out all values from my dictionary in a specific format, which would be line by line, separated by "-". I have already written the function print_person, to print it out in this format, I just want to apply this function (from the previous class) into my dict.
Here's the code:
class Person:
def __init__(self, name, phone,email):
self.name = name
self.phone = phone
self.email = email
def print_person(self):
return (str(self.name)+" - "+str(self.phone)+" - "+str(self.email))
class AddressBook:
def __init__ (self):
self.contactsdict = {}
def add(self, newContact):
self.contactsdict[newContact.name] = newContact.phone + " - " + newContact.email
def search(self, name):
return (self.contactsdict.get(name))
def addFromFile(self, fileName):
f = open("contacts.txt")
for line in f:
(key, val, val2) = line.split(",")
self.contactsdict[key] = val + " - " + val2
f.close
def printAddressBook(self):
for key, val in self.contactsdict.items():
Person.print_person
address = AddressBook() # make an instance
p1=Person("Danny Shalev","050-1111111","aaa#aaa.com")
print (p1.print_person())
address.add(p1)
address.addFromFile("contacts.txt")
address.printAddressBook()
I believe the problem is in this section, since I don't know how to use the method:
def printAddressBook(self):
for key, val in self.contactsdict.items():
Person.print_person

This
for key, val in self.contactsdict.items():
Person.print_person
deconstructs all your dictionary entries into 2 variables, one the key, the other the value. The second line is incorrrect - Person is your class, you need an instance of the class to use the defined print method on it.
You can call val.print_person() on each instance of the class Person to print each IF you store Persons in your inner dictionary. Classes are "templates" how a class is constructed - the instance must be used to call its functions. Currently your code only stores string in the internal dictionary.
To add persons to your internal Dict replace
for line in f:
(key, val, val2) = line.split(",")
self.contactsdict[key] = val + " - " + val2
with
for line in f:
(key, val, val2) = line.split(",")
self.contactsdict[key] = Person(key,val,val2) # create instances of Persons
# and store them in the dictionary by there name
# you get collisions if your file contains persons with identical names
Fixed code (this and some other errors marked with comments):
class Person:
def __init__(self, name, phone,email):
self.name = name
self.phone = phone
self.email = email
def print_person(self):
return (str(self.name) + " - " + str(self.phone) + " - " + str(self.email))
class AddressBook:
def __init__(self):
self.contactsdict = {}
def add(self, newContact):
self.contactsdict[newContact.name] = newContact # store the Person instance
# under its name as key
def search(self, name):
return (self.contactsdict.get(name))
def addFromFile(self, fileName):
f = open("contacts.txt")
for line in f:
(key, val, val2) = line.split(",")
self.add(Person(key,val,val2)) # create Person and use own add-Function
# to add it to internal dictionary
f.close
def printAddressBook(self):
for key, val in self.contactsdict.items():
print( val.print_person() ) # you need to print the output
# of print_person() - it currently only
# returns the string and does not print it
address = AddressBook() # make an instance
p1 = Person("Danny Shalev","050-1111111","aaa#aaa.com")
print(p1.print_person())
address.add(p1)
address.addFromFile("contacts.txt")
address.printAddressBook()
Search returns a person, so you can use it to change persons inside your dict:
print("")
p = address.search("Danny Shalev")
p.name = "Hallo" # change the name of the found person (the key will still be "Danny Shalev")
address.printAddressBook()
Output:
Danny Shalev - 050-1111111 - aaa#aaa.com
Gil Rom - 050-2222222 - bbb#bbb.com
Tal Yakir - 050-3333333 - ccc#ccc.com
Hallo - 050-1111111 - aaa#aaa.com # after change of searched person
Gil Rom - 050-2222222 - bbb#bbb.com
Tal Yakir - 050-3333333 - ccc#ccc.com

Related

Converting a textfile to a dictionary

My file:
Goal: to read a txt file and return dictionaries
What I have:
def load_snacks(snack_file: TextIO) -> Tuple[Dict[str, List[str]],
Dict[str, List[str]]]:
"""Return a two-item tuple containing a "healthysnack_to_junkfood" dictionary
and a "healthysnack_to_healthysnack" dictionary with the data from snack_file.
"""
snack_H2J = {}
snack_H2H = {}
line = snack_file.readline().strip()
while line != '':
# due to structure of the file, line contains a healthy snack name
healthysnack_name = line
# properly format the 1st healthy snack name, use helper fcn (see below for helper fcn)
flip_name_and_del_comma(healthysnack_name)
healthy_list = []
junk_list = []
line = snack_file.readline().strip()
while line != '\n':
if ',' in line:
snack_H2J[healthysnack_name] = line
a = flip_name_and_del_comma(line)
healthy_list.append(a)
else:
snack_H2H[healthysnack_name] = line
junk_list.append(line)
line = snack_file.readline().strip()
return (snack_H2J, snack_H2H)
Below is my helperfcn; I have verified that this works
def flip_name_and_del_comma(s: str) -> str:
""" Retrun a new str that reverses the format name order from 'colour, healthy snack name' to
'healthy snack name to colour'
>>> flip_name_and_del_comma('orange, carrot')
'carrot orange'
>>> flip_name_and_del_comma('yellow, mango')
'mango yellow'
"""
s_reversed = ', '.join(reversed(s.split(', ')))
s_comma_delete = s_reversed.replace(', ', ' ')
return s_comma_delete

Can't change instance attribute of my class?

I'm starting out in python and I can't quite figure out why I'm unable to change the data stored in one of my instance attributes. I have the following code:
class Bank:
def __init__(self, bank = 'Unnamed'):
self.bank = bank
self.clients = []
self.status = {'bank': self.bank, 'clients': self.clients}
self.c_counter=0
def deposit(self, name = None, amount = 200):
self.name = name
self.amount = amount
self.c_counter += 1
if self.name is None:
self.name = print("client" + str(self.c_counter));
self.clients.append((self.name, self.amount))
else:
self.clients.append((self.name, self.amount))
This produces the following output:
bb = Bank("bb")
bb.deposit(amount = 2000)
bb.status
out: {'bank': bb, 'clients': [(None, 2000)]}
While the desired output is:
out: {'bank': bb, 'clients': [('client1', 2000)]}
As you can see, what I'm trying to do is to set the client name to "clientx" if client name is not specified during a deposit; the x is just a number to distinguish each generic client from other generic clients without a specific name.
If a specific name is not provided when calling the deposit attribute of the bank the client name is set to None by default. I check this with the if condition and change the client name accordingly, but for some reason the client name literally gets added as "None" to the list of clients in the dictionary (list of tuples). What is wrong here?
print prints a string to sys.stdout and returns None. you should change the line
self.name = print("client" + str(self.c_counter));
to
self.name = "client" + str(self.c_counter)
or maybe self.name = f"client{self.c_counter}" for python >= 3.6.
print is a NoneType, it's None and you can prove it:
>>> type(print())
<class 'NoneType'>
>>>
And:
>>> print(print())
None
>>>
So print isn't be used for assigning, print is used for outputting stuff, whereas in this case you're assigning stuff, that which isn't meant for print to handle, so change:
self.name = print("client" + str(self.c_counter));
To:
self.name = "client" + str(self.c_counter)
Or:
self.name = "client%s" % self.c_counter
Or:
self.name = "client{}".format(self.c_counter)
Or if your python version is bigger or equal to 3.6, you can use:
self.name = f"client{self.c_counter}"

Properly using dataclasses to return values of items

The project is to sort items - using a particular algorithm - into boxes. I am having trouble after assigning each items to the proper class, to return to another function and use and modify the data held within the object in the data class.
My testing file looks like this:
17 10 4
Abacus 3
Blender 5
Chessboard 3
Dishes 6
My classes:
#dataclass
class InventoryItem:
name: str
weight: float
#dataclass
class BoxInventory:
name: str
maxWeight: float
remainingWeight: float
contents: dict = ""
"""
def listContents(self, contents):
self.listContents = contents
def remainingWeight(self, remainingWeight):
self.remainingWeight = remainingWeight
def addItemWeight(self, itemWeight):
self.remainingWeight -= itemWeight
def addItemList(self, itemName, itemWeight, contents):
self.contents = contents[itemName] = contents[itemWeight]
"""
Here is where I read my text file and transfer it to a class:
"""
Take the given txt file and format into proper list for boxes and items
:param filename: The filename of the text file
:return: Send lists to to be used by an algo.
"""
with open(filename, 'r') as myFile: # Open the correct file
itemDict = {}
boxDict = {}
myList = [line.split() for line in myFile.readlines()]
boxLine = ' '.join(myList[0])
for line in range(1, len(myList)):
lines = ''.join(myList[line])
itemName = lines[:-1]
weight = lines[len(lines) - 1:]
item = InventoryItem(itemName, int(weight))
itemDict[itemName] = [item]
boxString = ""
count = 0
for char in boxLine:
if char != " ":
boxString = boxString + char
else:
boxName = "Box" + str(count)
box = BoxInventory(boxName, int(boxString), int(boxString))
boxDict[boxName] = [box]
boxString = ""
count += 1
myReturn = {}
myReturn['boxDict'] = boxDict
myReturn['itemDict'] = itemDict
return myReturn
Non-implemented algorithm:
def roomiest(myReturnDict):
"""
For each item find the box with the greatest remaining allowed weight that can support the item and place the item in that box
:param boxList: The list of boxes in the class from the given file
:param itemList: The list of items in the class from the given file
:return: If boxes were able to fit all items(1); items in box with individual weights(2); Box name with max
weight(3); items with their weights that were left behind(4)
"""
itemList = myReturnDict.get("itemDict")
boxList = myReturnDict.get("boxDict")
My problem is that I do know how to read the parsed data from my
fileReader function in my algo. function.
Your input function is a little strange as you're storing the objects in a list of length 1 inside a dictionary. So your data looks like:
'Dishes': [InventoryItem(name='Dishes', weight=6)]
instead of
'Dishes': InventoryItem(name='Dishes', weight=6)
You might have a reason for it, but changing itemDict[itemName] = [item] to itemDict[itemName] = item makes your code a little easier to follow (and the same for boxDict[boxName] = [box]). With that change you can access the parsed data easily with the following:
for item_name, item in itemList.items():
print(item.name)
print(item.weight)
This iterates through the itemList dictionary, getting the key, value pairs which in this case is itemName, item (or [item] in your original code. If you don't want to change that, replace item with item[0] in the code above). Then you can access attributes of your Class directly by calling their label.
You can get the box with most space remaining, using
sorted_box_list = (sorted(boxList.values(), key=operator.attrgetter('remainingWeight'), reverse=True))
What I have done is rather than using a dictionay I am using a list to pass on the data to a new function.
Text File --> List --> Dict --> List --> sortedList
Here is my new fileReader function:
def fileReader(filename):
"""
Take the given txt file and format into proper list for boxes and items
:param filename: The filename of the text file
:return: Send lists to to be used by an algo.
"""
with open(filename, 'r') as myFile: # Open the correct file
itemList = []
boxList = []
myList = [line.split() for line in myFile.readlines()]
boxLine = ' '.join(myList[0])
for line in range(1, len(myList)):
lines = ''.join(myList[line])
itemName = lines[:-1]
weight = lines[len(lines) - 1:]
item = InventoryItem(itemName, int(weight))
itemList.append(item)
boxString = ""
count = 0
for char in boxLine:
if char != " ":
boxString = boxString + char
else:
boxName = "Box" + str(count)
box = BoxInventory(boxName, int(boxString), int(boxString))
boxList.append(box)
boxString = ""
count += 1
I then read and sort the data in each algotithm using this same method:
def roomiest(myReturnDict):
"""
For each item find the box with the greatest remaining allowed weight that can support the item and place the item in that box
:param boxList: The list of boxes in the class from the given file
:param itemList: The list of items in the class from the given file
:return: If boxes were able to fit all items(1); items in box with individual weights(2); Box name with max
weight(3); items with their weights that were left behind(4)
"""
itemData = list(myReturnDict.get("itemList"))
boxData = list(myReturnDict.get("boxList"))
sortedItemList = sorted(itemData, key=lambda x: x.weight, reverse=True)
sortedBoxList = sorted(boxData, key=lambda x: x.remainingWeight, reverse=True)
myReturn = {}
myReturn['boxList'] = boxList
myReturn['itemList'] = itemList
return myReturn
My dataclasses look like the following:
#dataclass
class InventoryItem:
name: str
weight: float
#dataclass
class BoxInventory:
name: str
maxWeight: float
remainingWeight: float
contents: dict = ""
def itemWeight(item):
print("Weight of", item.name, "is: ", item.weight, "\n")
return item.weight
def remainWeight(box):
print("Rem. weight in ", box.name, "is: ", box.remainingWeight, "\n")
return box.remainingWeight

Never resets list

I am trying to create a calorie counter the standard input goes like this:
python3 calories.txt < test.txt
Inside calories the food is the following format: apples 500
The problem I am having is that whenever I calculate the values for the person it seems to never return to an empty list..
import sys
food = {}
eaten = {}
finished = {}
total = 0
#mappings
def calories(x):
with open(x,"r") as file:
for line in file:
lines = line.strip().split()
key = " ".join(lines[0:-1])
value = lines[-1]
food[key] = value
def calculate(x):
a = []
for keys,values in x.items():
for c in values:
try:
a.append(int(food[c]))
except:
a.append(100)
print("before",a)
a = []
total = sum(a) # Problem here
print("after",a)
print(total)
def main():
calories(sys.argv[1])
for line in sys.stdin:
lines = line.strip().split(',')
for c in lines:
values = lines[0]
keys = lines[1:]
eaten[values] = keys
calculate(eaten)
if __name__ == '__main__':
main()
Edit - forgot to include what test.txt would look like:
joe,almonds,almonds,blue cheese,cabbage,mayonnaise,cherry pie,cola
mary,apple pie,avocado,broccoli,butter,danish pastry,lettuce,apple
sandy,zuchini,yogurt,veal,tuna,taco,pumpkin pie,macadamia nuts,brazil nuts
trudy,waffles,waffles,waffles,chicken noodle soup,chocolate chip cookie
How to make it easier on yourself:
When reading the calories-data, convert the calories to int() asap, no need to do it every time you want to sum up somthing that way.
Dictionary has a .get(key, defaultvalue) accessor, so if food not found, use 100 as default is a 1-liner w/o try: ... except:
This works for me, not using sys.stdin but supplying the second file as file as well instead of piping it into the program using <.
I modified some parsings to remove whitespaces and return a [(name,cal),...] tuplelist from calc.
May it help you to fix it to your liking:
def calories(x):
with open(x,"r") as file:
for line in file:
lines = line.strip().split()
key = " ".join(lines[0:-1])
value = lines[-1].strip() # ensure no whitespaces in
food[key] = int(value)
def getCal(foodlist, defValueUnknown = 100):
"""Get sum / total calories of a list of ingredients, unknown cost 100."""
return sum( food.get(x,defValueUnknown ) for x in foodlist) # calculate it, if unknown assume 100
def calculate(x):
a = []
for name,foods in x.items():
a.append((name, getCal(foods))) # append as tuple to list for all names/foods eaten
return a
def main():
calories(sys.argv[1])
with open(sys.argv[2]) as f: # parse as file, not piped in via sys.stdin
for line in f:
lines = line.strip().split(',')
for c in lines:
values = lines[0].strip()
keys = [x.strip() for x in lines[1:]] # ensure no whitespaces in
eaten[values] = keys
calced = calculate(eaten) # calculate after all are read into the dict
print (calced)
Output:
[('joe', 1400), ('mary', 1400), ('sandy', 1600), ('trudy', 1000)]
Using sys.stdin and piping just lead to my console blinking and waiting for manual input - maybe VS related...

Python: print dictionary keys and values individually

I'm wondering: how do you print the keys or the values individually from a dictionary in a function?
Example .txt file
00000000;Pikachu Muchacho;region1
11111111;SoSo good;region2
22222222;Marshaw williams;region3
33333333;larry Mikal Carter;region3
Code
test_file = open("test.txt", "r")
customer = {}
def dictionary():
for line in test_file:
entries = line.split(";")
key = entries[0]
values = entries[1]
customer[key] = values
def test():
print(customer)
print(customer[key])
def main():
dictionary()
test()
main()
As #jamesRH commented, you can use customer.keys() and customer.values():
test_file = open("test.txt", "r")
customer = {}
def dictionary():
for line in test_file:
entries = line.split(";")
key = entries[0]
values = entries[1]
customer[key] = values
def test():
# Print all the keys in customer
print(customer.keys())
# Print all the values in customer
print(customer.values())
def main():
dictionary()
test()
main()
This gives the output:
['00000000', '22222222', '33333333', '11111111']
['Pikachu Muchacho', 'Marshaw williams', 'larry Mikal Carter', 'SoSo good']
Your original code causes an error because key is not within the scope of test().

Resources