Python Forum
Dictionary based assignment: Need help
Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Dictionary based assignment: Need help
#1
I've been tasked with creating a program for a hypothetical bike store. We've been given two text documents, one filled with bike parts and the other filled with whole bikes. Both are formatted:
"ID Name Price"
But in the product document, the prices are a collection of all of the part prices and I'm unable to find any help with writing the code that tallys all the prices together and prints the final result.

I also need help writing the user input part of the program, eg the program hs to ask if I'm looking for a part or a product, then the name or the price and respond with the correct information. The link to my github page is listed below the python code that I have so far, any help will be much appreciated.

def load_parts(textfile):   ##Establishes where the parts file is
    parts_file = open(textfile, 'r')
    parts = parts_file.readlines()
    parts_file.close()
    return parts

def load_products(textfile):    ##Establishes where the product file is
    products_file = open(textfile, 'r')
    products = products_file.readlines()
    products_file.close()
    return products

parts_data = load_parts('parts.txt') #Don't know what this does but it works
products_data = load_products('products.txt')

partNames = {} ##Establishes the dictionaries of the part & product names

partPrices = {}

productNames = {}

productParts = {}


for line in parts_data: ##Handles queries regarding parts data & strips the unnecessary information
    splitted_line = line.split(',')
    if len(splitted_line) == 1:
        continue
    ID = splitted_line[0].strip()
    Name = splitted_line[1].strip()
    Price = splitted_line[2].strip()
    
    partNames[ID] = Name
    partPrices[ID] = Price



for line in products_data:          ##Copied from above to handle the product queries & strips unnecessary info.  
    splitted_line = line.split(',') ##This isn't quite finished, need help with this
    if len(splitted_line) == 1:
        continue
    ID = splitted_line[0].strip()
    Name = splitted_line[1].strip()
    Price = splitted_line[2].strip()
    
    productNames[ID] = Name
    productParts[ID] = Price
    
##Below I pulled from an example my teacher gave me but I still need to apply it to this program, need help ##with this

##for x in parts_data:
##     print(x)
##     print('-------------------------------')
##
##run = True
##
##while run:
##    command = input("Please give a command\n")
##    
##    if command[0] == 'a':
##        command = command.split(' ')
##        print("Command recieved: " + command[0])
##        print("Searching for: " + command[1])
##        
##    if command[0] == 'b':
##        print("Execute order 66")
https://github.com/RoyceJ/Dictionary-Assessment---Python-3
Reply
#2
Disclaimer: all following can be considered as ranting

I found task description in github (Assessment file) to be very ambiguous. Every time I encounter such poorly defined tasks I become mean Monty. This made me provide some ideas below which are as bad (but should be working).

If .txt files in github are in correct format (no header rows, blank lines, empty spaces after commas etc) one could use csv.DictReader for files and do something along those lines:

import csv

with open('parts.txt', 'r') as f:
    fieldnames = ('PartID', 'Partname', 'PartCost')
    parts = list(csv.DictReader(f.readlines(), fieldnames=fieldnames, skipinitialspace=True))

with open('products.txt', 'r') as d:
    fieldnames = ('BikeID', 'BikeName')
    products = list(csv.DictReader(d.readlines(), 
                                   fieldnames=fieldnames, 
                                   restkey='BikeParts', 
                                   skipinitialspace=True))
Data is now stored in OrderedDict-s and we can use brute force to iterate over data (bad idea, but we are strong). We can construct iteration in a such way that we will get UnboundLocalError if there is no match and use it to return 'Invalid ID'.

To get name from ID:

def get_name(ID):
    try: 
        if ID.startswith('bike'):
            for row in products:
                if row['BikeID'] == ID:
                    name = row['BikeName']
        else:
            for row in parts:
                if row['PartID'] == ID:
                    name = row['Partname']
        return name
    except UnboundLocalError:
        return 'Invalid ID'
To get cost of bike parts:

def parts_cost(bike_id):
    try:
        for row in products:
            if row['BikeID'] == bike_id:
                cost = 0
                for item in row['BikeParts']:
                    part_id, qty = item.split(':')
                    for row in parts:
                        if part_id == row['PartID']:
                            cost += int(row['PartCost']) * int(qty)
        return cost
    except UnboundLocalError:
        return 'Invalid ID'
As mentioned, it is brute force. One should not iterate over (all) rows again and again; should break out of loop if desired result is achieved; should keep nesting level manageable.
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply
#3
(Aug-21-2018, 04:55 PM)perfringo Wrote: I found task description in github (Assessment file) to be very ambiguous. Every time I encounter such poorly defined tasks I become mean Monty. This made me provide some ideas below which are as bad (but should be working).

Thanks for your help, I've implemented (not very well) it into what I've got so far and it works a treat. I've kept a lot of the old code but we're being marked on the program not the code so as far as I'm concerned it doesn;t matter how poor the code is.

Everything works and has been uploaded into a new file: CSV Testing File; you're welcome to critique oor criticise as you please.
Reply
#4
Implemented almost everything. Everything I have scripted works just fine, I have a couple tweaks in mind but I'll come back to that when everything is scripted and working correctly. I still need to add a part that will take the name of the product and give you the names of all the parts and the amount needed, then the cost. Ideally, each of them are all on new lines.
EG:

Mountian Bike
$900
To build this you will need
2x Mountian Bike Wheels $100
1x Mountain Bike Frame $1200
etc

Need really sure how to split all the products, then put them on new lines.
Reply
#5
Task (from assignment file in Github):

Mr Person has given the following list of functions that need to be implemented into the program.
- Given a BikeID, print a list of all the parts’ PartID and how many of each part required to build the bike.
- Given a BikeName or PartName, print the BikeID or PartID respectively.
- Given a BikeID or a PartID, print the BikeName or PartName respectively.
- Given a BikeID, print the calculated cost of all the parts required to build it.
- Given a BikeID or a PartID that is not valid as part of any command, print “Invalid ID”
- Given any other input, print “Invalid Command”.
- And finally a way close the catalogue.

I can't find anything which is along those lines: "take the name of the product and give you the names of all the parts and the amount needed, then the cost. Ideally, each of them are all on new lines.". There is only one case with BikeName and it must return ID. Does assignment file contain all requirements or there are some more somewhere else?

One of the reasons I am angry with wording of this assignment is that there is no instructions about user interface. As it written right now, I would assume that there is only one instance of user input ('Please enter Name or ID: ') and in response of user entering ID all needed data should be displayed. There is nothing which indicates that I should determine what kind information is required and display only that.


Some feedback about code.

I noticed:

run = True

while run:
I can do just:

while True: 
You can write little helper function to validated user input if you want determine what kind of information to display.

def ask(question):
    """Return allowed answer."""
    allowed = ['BikeID', 'PartID', 'BikeName', 'PartName']
    while True:
        answer = input(question)
        if answer in allowed:
            return answer
        else:
            print((f'Expected one choice from: {", ".join(allowed)} ' 
                   f'but got {answer}'))
Then just:

>>> ask('Please enter name or ID type: ')
Please enter name or ID type: bike
Expected one choice from: BikeID, PartID, BikeName, PartName but got bike
Please enter name or ID type: BikeName
'BikeName'
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply
#6
(Aug-27-2018, 04:51 AM)perfringo Wrote: I can't find anything which is along those lines: "take the name of the product and give you the names of all the parts and the amount needed, then the cost.
One of the reasons I am angry with the wording of this assignment is that there is no instructions about user interface. As it written right now, I would assume that there is only one instance of user input ('Please enter Name or ID: ') and in response of user entering ID all needed data should be displayed. There is nothing which indicates that I should determine what kind information is required and display only that.


My mistake, the program just needs to spit out all of the PartID's and the quantity needed. The user interface doesn't matter in the slightest as long as we fulfill all of the requirements, the only thing I need to do is have it print all of the PartID's in a product and the quantity and then I'm done. My teacher is really painful to deal with so I don't really care that much about the UI.
Reply
#7
List of parts and quantity can be obtained quite easily. I don't know whether is in correct format or not:

def parts_list(bike_id):
    for row in products:
        if row['BikeID'] == bike_id:
            return row['BikeParts']
Which will produce:

>>> parts_list('bike301')
['WH339:2', 'TR302:2', 'TU377:2', 'FR301:1', 'FB301:1', 'BB301:1', 'GS301:1']
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Dictionary based exercise garvind25 2 1,921 Jul-12-2020, 06:53 PM
Last Post: garvind25
  Powerball assignment, how to get correct output of a dictionary ? msp1981 5 3,222 Mar-19-2019, 11:02 PM
Last Post: Yoriz
  logic comparater based on dictionary values ijosefson 3 3,183 Oct-16-2017, 06:04 AM
Last Post: Mekire

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020