0

I have a spreadsheet of values for subway lines and their stops. Basically, I am trying to iterate over the CSV file so that when you input a train line it spits out all the stops. I am doing this by creating a dictionary where the key is the train line and the values are a list of the stops. I am telling the function to append but when I print it only shows the last value on the sheet. Thanks for your help!

import os;
class MTALines:
    def __init__(self,train="",stop_name=""):
        self.__points=[];
        self.train=train;
        self.stop_name=stop_name;
    def addLine(self,stop_name):
        self.__points.append(self.stop_name);
    def __repr__(self):
        string=""
        for item in self.__points:
            string+=item+","
        return string

def main():
    inFile = open("hw8 - mta train stop data.csv", "r")
    header = inFile.readline();

    MTA={};
    for line in inFile:
        parts = line.split(',');
        stop_id=parts[0]
        train=stop_id[0]
        stop_name=parts[2]
        getstops = MTALines(train,stop_name);
        getstops.addLine(stop_name);
        MTA[train] = getstops;        


    trainline=""
    while trainline!="done":
        trainline=input("Please enter a train line, or 'done' to stop: ")
        print(trainline,"line:",MTA[trainline])


main();

Update:

As requested here are a few lines of the CSV file:

stop_id,stop_code,stop_name,stop_desc,stop_lat,stop_lon,zone_id,stop_url,location_type,parent_station
101,,Van Cortlandt Park - 242 St,,40.889248,-73.898583,,,1,
101N,,Van Cortlandt Park - 242 St,,40.889248,-73.898583,,,0,101
101S,,Van Cortlandt Park - 242 St,,40.889248,-73.898583,,,0,101
209S,,Burke Av,,40.871356,-73.867164,,,0,209
210,,Allerton Av,,40.865462,-73.867352,,,1,
210N,,Allerton Av,,40.865462,-73.867352,,,0,210
210S,,Allerton Av,,40.865462,-73.867352,,,0,210
3
  • 2
    Thanks for posting such a well formatted piece of python code. This is unusual on stackoverflow. btw you may not need as many semi-colons as you think. Commented May 4, 2018 at 13:11
  • I'm not sure I understand the problem. Inside the loop, you create an independent MTALines object for each line of the file. Then you append a single line to that object. So it's not surprising to me that when you print any one MTALines instance, you only see one line. If you want a single MTALines with many stops, then you should only create one MTALines, and add lines only to that. Commented May 4, 2018 at 13:12
  • How are you splitting the data? You have train=stop_id[0] which is essentially the first char of each line. How is this a train? Commented May 4, 2018 at 13:41

3 Answers 3

2

I think you're making this task a little more complicated than it needs to be. You don't really need a custom MTALines class, you can store the data for each stop in a dict, each line can be a list of those dicts, and each line list can live in the MTA dict. It's convenient to use a defaultdict for MTA, as that will automatically create new lists as needed.

Also, there's no need to parse the CSV file data by hand, there's a csv module for that. And by using its DictReader class we can get it to read the data into a dict. It actually uses OrderedDict, to preserve the order of the fields.

Here's my version of your code. I changed the name of the CSV file because I hate filenames with spaces in them. ;) Because we're using a defaultdict of lists for MTA if we try to look up a non-existent line we get an empty list.

import csv
from collections import defaultdict

def main():
    MTA = defaultdict(list)
    with open("train_data.csv", "r") as inFile:
        reader = csv.DictReader(inFile)
        #print(reader.fieldnames)
        for row in reader:
            # Get the line id from the stop id
            train = row['stop_id'][0]
            # Extract the desired fields to a new dict
            data = {'stop_id': row['stop_id'], 'stop_name': row['stop_name']}
            MTA[train].append(data)

    while True:
        line_id = input("Please enter a train line, or 'done' to stop: ")
        if line_id == "done":
            break
        print("line:", line_id)
        for stop in MTA[line_id]:
            print(stop['stop_id'], stop['stop_name'])

main()

demo output

Please enter a train line, or 'done' to stop: 1
line: 1
101 Van Cortlandt Park - 242 St
101N Van Cortlandt Park - 242 St
101S Van Cortlandt Park - 242 St
Please enter a train line, or 'done' to stop: 2
line: 2
209S Burke Av
210 Allerton Av
210N Allerton Av
210S Allerton Av
Please enter a train line, or 'done' to stop: 3
line: 3
Please enter a train line, or 'done' to stop: done
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much!
1

I think you may need a defaultdict to collect lists of MTALines instances.

It looks like your dict MTA may overwrite entries if the same train occurs multiple times.

Try this:

from collections import defaultdict

...

def main():
    inFile = open("hw8 - mta train stop data.csv", "r")
    header = inFile.readline()

    MTA = defaultdict(list)  # create defaultdict here
    for line in inFile:
        parts = line.split(',')
        stop_id = parts[0]
        train = stop_id[0]
        stop_name = parts[2]
        getstops = MTALines(train,stop_name)
        getstops.addLine(stop_name)
        MTA[train].append(getstops)   # append to list of MTALines 
    ...

Now the 'problem' might be how to format an entry from the MTA collection:

print(trainline, "line:", MTA[trainline])

Comments

0

Your problem is that you made __points as an instance variable. It will only be available for the instance. Obviously you will get the last stop or last instance value. For a quick fix, use __points as class variable like below.

class MTALines:
    __points=[];
    def __init__(self,train="",stop_name=""):
        self.train=train;
        self.stop_name=stop_name;
    def addLine(self,stop_name):
        MTALines.__points.append(self.stop_name);
    def __repr__(self):
        string=""
        for item in self.__points:
            string+=item+","
        return string

At the end you can use your list as MTALines.__points

2 Comments

yeah probably a typo. Edited. Thank you.
I didn't downvote (or upvote), but I don't think your code does what the OP wants, or what you expect. It combines all the lines into one list.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.