0

Is there some easy way to access an object in a list, without using an index or iterating through the list?

In brief: I'm reading in lines from a text file, splitting up the lines, and creating objects from the info. I do not know what information will be in the text file. So for example:

roomsfile.txt

0\bedroom\A bedroom with king size bed.\A door to the east.

1\kitchen\A modern kitchen with steel and chrome.\A door to the west.

2\familyRoom\A huge family room with a tv and couch.\A door to the south.

Some Python Code:

class Rooms:
    def __init__(self, roomNum, roomName, roomDesc, roomExits):
        self.roomNum = roomNum
        self.roomName = roomName
        self.roomDesc = roomDesc
        self.roomExits = roomExits

    def getRoomNum(self):
        return self.roomNum

    def getRoomName(self):
        return self.roomName

    def getRoomDesc(self):
        return self.roomDesc

    def getRoomExits(self):
        return self.roomExits

def roomSetup():
    roomsfile = "roomsfile.txt"
    infile = open(roomsfile, 'r')
    rooms = []
    for line in infile:
        rooms.append(makeRooms(line))
    infile.close()
    return rooms

def makeRooms(infoStr):
    roomNum, roomName, roomDesc, roomExits = infoStr.split("\")
    return Rooms(roomNum, roomName, roomDesc, roomExits)

When I want to know what exits the bedroom has, I have to iterate through the list with something like the below (where "noun" is passed along by the user as "bedroom"):

def printRoomExits(rooms, noun):
    numRooms = len(rooms)
    for n in range(numRooms):
        checkRoom = rooms[n].getRoomName()
        if checkRoom == noun:
            print(rooms[n].getRoomExits())
        else:
            pass

This works, but it feels like I am missing some easier approach...especially since I have a piece of the puzzle (ie, "bedroom" in this case)...and especially since the rooms list could have thousands of objects in it.

I could create an assignment:

bedroom = makeRooms(0, bedroom, etc, etc)

and then do:

bedroom.getRoomExits()

but again, I won't know what info will be in the text file, and don't know what assignments to make. This StackOverFlow answer argues against "dynamically created variables", and argues in favor of using a dictionary. I tried this approach, but I could not find a way to access the methods (and thus the info) of the named objects I added to the dictionary.

So in sum: am I missing something dumb?

Thanks in advance! And sorry for the book-length post - I wanted to give enough details.

chris

Community
  • 1
  • 1
  • 2
    "...in favor of using a dictionary. I tried this approach, but I could not find a way to access the methods (and thus the info) of the named objects I added to the dictionary." Accessing a dictionary is the same as accessing a list, in a way. If you can do list[0].doMethod(), you can also do dict["bedroom"].doMethod(). – Patashu Jun 05 '13 at 04:38
  • 1
    if its a sorted list, ie you have all the rooms in alphabetical order, its easier. See [this](http://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-an-unsorted-array) – Darcys22 Jun 05 '13 at 04:40

3 Answers3

1

You can use in to check for membership (literally, if something is in a container). This works for lists, strings, and other iterables.

>>> li = ['a','b','c']
>>> 'a' in li
True
>>> 'x' in li
False
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
1

At least one dictionary is the right answer here. The way you want to set it up is at least to index by name:

def roomSetup():
    roomsfile = "roomsfile.txt"
    infile = open(roomsfile, 'r')
    rooms = {}
    for line in infile:
        newroom = makeRooms(line)
        rooms[newroom.roomName] = newroom
    infile.close()
    return rooms

Then, given a name, you can access the Rooms instance directly:

exits = rooms['bedroom'].roomExits

There is a reason I'm not using your getRoomName and getRoomExits methods - getter and setter methods are unnecessary in Python. You can just track your instance data directly, and if you later need to change the implementation refactor them into properties. It gives you all the flexibility of getters and setters without needing the boilerplate code up front.

Depending on what information is present in your definitions file and what your needs are, you can get fancier - for instance, I would probably want to have my exits information stored in a dictionary mapping a canonical name for each exit (probably starting with 'east', 'west', 'north' and 'south', and expanding to things like 'up', 'down' and 'dennis' as necessary) to a tuple of a longer description and the related Rooms instance.

I would also name the class Room rather than Rooms, but that's a style issue rather than important behavior.

Peter DeGlopper
  • 36,326
  • 7
  • 90
  • 83
  • Peter, Burhan, and Vaughn - thanks for the replies! This was very helpful. I got it working. But I realized I need it to access the info by index sometimes, so I started messing with OrderedDict. But rooms.items()[n] does not work (I get "TypeError: 'ItemsView' object does not support indexing"). Something seems to have changed since: http://stackoverflow.com/questions/10058140/accessing-items-in-a-ordereddict – user2454099 Jun 05 '13 at 21:29
  • Yeah, that answer was correct as written for 2.7 but not for Python 3. You can work around it by using `list(rooms.values())[n]`, or save the list version as well after creating your dictionary (eg `rooms_by_index = list(rooms.values())`) and referencing it as needed. Depending on whether you ever change your rooms after it's initially created, anyway. – Peter DeGlopper Jun 05 '13 at 21:49
  • Thanks, Peter. I gave list(rooms.values())[n]) a try, but got a "TypeError: 'ValuesView' object does not support indexing" error. But I tried your second suggestion (list(rooms.values()) and that worked great! Updating a value in the dict also updated the objects value in the list, which surprised me a little but it's what I want. Thanks for all the help! – user2454099 Jun 06 '13 at 04:58
0

After you've read your rooms, you can create a dictionary:

rooms = roomSetup()

exits_of_each_room = {}

for room in rooms:
  exits_of_each_room[room.getRoomName()] = room.getRoomExits()

Then you your function is simply:

def printRoomExits(exits_of_each_room, noun):
    print exits_of_each_room[noun]
Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132