Splits
Calvin (Deutschbein)
W13Wed: 20 Nov
Announcements
- Adventure Ongoing
- At least finish Milestone 0: TM -> ADV, to give your brain time to think
- Advising ongoing
- If you encounter any problem, email me immediately
- I'll be doing triage:
- If you don't get an email back quickly, either
- the problem is not urgent and I'll solve it latter, or
- I am fleeing a zamboni IRL and require thoughts & prayers stat.
Adventure
- Read files.
- Put them in records.
- Print out parts of records based on user input.
- Many ways to read files:
- The book uses a token scanner class
- Today I will teach you to use the ".splits()" method of strings.
First Example: SmallSynonyms.txt
- It's here.
- Basically we want to turn this file into a dictionary.
- It looks like this:
N=NORTH
S=SOUTH
E=EAST
W=WEST
U=UP
D=DOWN
Q=QUIT
L=LOOK
I=INVENTORY
CATCH=TAKE
RELEASE=DROP
BOTTLE=WATER
First Example: SmallSynonyms.txt
- Basically we want to turn this file into a dictionary.
N=NORTH
S=SOUTH
E=EAST
W=WEST
- Keys will be the strings on the left hand side (LHS) of the single equals ("=").
- Values will be the strings on the right hand side (RHS) of the single equals ("=").
- Basically:
>>> d = {'N':'NORTH', 'S':'SOUTH'}
>>> d
{'N': 'NORTH', 'S': 'SOUTH'}
>>> d['N']
'NORTH'
First Example: SmallSynonyms.txt
- We can "read" the file into a string like so:
synonyms = open("SmallSynonyms.txt").read()
- If we print out synonyms, it will give you back the text of the file.
- Values will be the strings on the right hand side (RHS) of the single equals ("=").
>>> file_text = open("SmallSynonyms.txt").read()
>>> print(file_text)
N=NORTH
S=SOUTH
...
- I want to turn this into a dictionary.
First Example: SmallSynonyms.txt
- I ask:
- What corresponds to an element of my dictionary, and
- What separates each element?
- I note first that key-value pairs, the elements of a dictionary, are separated by lines.
- I can split the string on the special newline character to get a list of lines.
>>> file_text
'N=NORTH\nS=SOUTH\nE=EAST\nW=WEST\n...'
>>> kvps = file_text.split("\n") # key value pairs
>>> kvps
['N=NORTH', 'S=SOUTH', 'E=EAST', 'W=WEST'...
>>>
- I want to turn this into a dictionary.
First Example: SmallSynonyms.txt
- I ask:
- What corresponds to an element of my dictionary, and
- What separates each element?
- I note that the keys and values are separated by single equals "="
- I loop over the list and split each string in the list on "=".
>>> kvps
['N=NORTH', 'S=SOUTH', 'E=EAST', 'W=WEST'...
>>> knvs = [kvp.split("=") for kvp in kvps] # keys n values
>>> knvs
[['N', 'NORTH'], ['S', 'SOUTH'], ['E', 'EAST'], ['W', 'WEST'], ...
- I want to turn this into a dictionary.
First Example: SmallSynonyms.txt
- I ask:
- What corresponds to an element of my dictionary, and
- What separates each element?
- I note that the keys and values are separated by single equals "="
- I loop over the list and split each string in the list on "=".
>>> knvs = [kvp.split("=") for kvp in kvps] # keys n values
>>> knvs
[['N', 'NORTH'], ['S', 'SOUTH'], ['E', 'EAST'], ['W', 'WEST'], ...
- I want to turn this into a dictionary.
First Example: SmallSynonyms.txt
- I ask:
- What corresponds to an element of my dictionary, and
- What separates each element?
- I now have a list of lists of keys and values.
- A list of key value pairs, perhaps.
- I create a dictionary that loops over the list, like so:
>>> knvs
[['N', 'NORTH'], ['S', 'SOUTH'], ['E', 'EAST'], ['W', 'WEST'], ...
>>> {key:value for key,value in knvs}
- This draws the following ValueError: "not enough values to unpack (expected 2, got 1)"
First Example: SmallSynonyms.txt
- I ask:
- What corresponds to an element of my dictionary, and
- What separates each element?
- We debug:
- We write out a for loop.
- We print every value.
syns = { }
for knv in knvs:
print("knv is", knv)
key, value = knv
syns[key] = value
- We see this at the end:
knv is ['']
Traceback (most recent call last):
...
First Example: SmallSynonyms.txt
- I ask:
- What corresponds to an element of my dictionary, and
- What separates each element?
- We debug:
- There was an empty line at the end of the file.
- It had no text, so no synonym, so no key or value!
- We use an if statement, like checking if length is equal to 2.
syns = { }
for knv in knvs:
if len(knv) == 2:
key, value = knv
syns[key] = value
- It works:
>>> syns
{'N': 'NORTH',
...
First Example: SmallSynonyms.txt
- I ask:
- What corresponds to an element of my dictionary, and
- What separates each element?
- We could use an "if" in the comprehension:
>>> knvs
[['N', 'NORTH'], ['S', 'SOUTH'], ['E', 'EAST'], ['W', 'WEST'], ...
>>> {knv[0]:knv[1] for knv in knvs if len(knv) == 2}
{'N': 'NORTH', 'S': 'SOUTH', ...
- Or just clip off the last, empty line.
>>> knvs
[['N', 'NORTH'], ['S', 'SOUTH'], ['E', 'EAST'], ['W', 'WEST'], ...
>>> {key:value for key,value in knvs[:-1]}
{'N': 'NORTH', 'S': 'SOUTH', ...
First Example: SmallSynonyms.txt
- I ask:
- What corresponds to an element of my dictionary, and
- What separates each element?
- Here is a complete file to read synonyms into a dictionary:
file = open("SmallSynonyms.txt").read()
kvps = file.split("\n")
knvs = [kvp.split("=") for kvp in kvps]
syns = {key:value for key,value in knvs[:-1]}
print(syns)
- For the advanced student, this can be done in a single step:
syns = {key:value for key,value in [kvp.split("=") for kvp in open("SmallSynonyms.txt").read().split("\n")][:-1]}
- This code may help you on Milestone 5.
Second Example: SmallItems.txt
- It's here.
- Basically we want to turn this file into a dictionary.
- It looks like this:
KEYS
a set of keys
InsideBuilding
LAMP
a brightly shining brass lamp
BeneathGrate
ROD
a black rod with a rusty star
DebrisRoom
WATER
a bottle of water
PLAYER
Second Example: SmallItems.txt
- Basically we want to turn this file into a dictionary?
- Well - a dictionary of dictionaries.
- We want to be able to place any item in any room.
- We want items to have a known name (key) and description (value).
- Ultimately, the way items work is:
{ "InsideBuilding": { "KEYS" : "a set of keys" }}
- So we have outer keys (rooms), inner keys (items), and inner values (item descriptions).
- This is just JSON by the way.
Second Example: SmallItems.txt
- We note:
- We have key-key-value entries separated by double new-lines.
>>> file_text = open("SmallItems.txt").read()
>>> file_text
'KEYS\na set of keys\nInsideBuilding\n\nLAMP
- Emphasis here:
\n\nLAMP
- So we can get a list of strings, where each string corresponds to an item, like so:
>>> items = file_text.split("\n\n")
>>> items
['KEYS\na set of keys\nInsideBuilding', 'LAMP...
Second Example: SmallItems.txt
- Within each item we can get outer keys, inner keys, and inner values by splitting on the newline character '\n'
>>> items
['KEYS\na set of keys\nInsideBuilding', 'LAMP'...
>>>
>>> in_val_outs = [item.split("\n") for item in items]
>>> in_val_outs
[['KEYS', 'a set of keys', 'InsideBuilding'], ['LAMP', 'a brightly shining brass lamp', 'BeneathGrate'],...
Second Example: SmallItems.txt
- Notice that this construction:
[item.split("\n") for item in items]
- Is very similar to what we did with synonyms:
[kvp.split("=") for kvp in kvps]
- Your takeaways should be:
- Knowing a few methods helps a lot.
- Knowing how to provide even one argument to a method solves many problems.
- If you are systematic and take small steps, every step is easy.
- Once you know the steps, you can make more advanced plans like "dictionary of dictionaries".
Second Example: SmallItems.txt
- I created a dictionary where the values were the first two elements and the key was the element of index 2.
>>> in_val_outs
[['KEYS', 'a set of keys', 'InsideBuilding'], ['LAMP', 'a brightly shining brass lamp', 'BeneathGrate'],...
>>>
>>> room_contents = {ivo[2]:ivo[:2] for ivo in in_val_outs}
>>> room_contents
{'InsideBuilding': ['KEYS', 'a set of keys'],
Second Example: SmallItems.txt
- Except of course, I don't want the values to be lists, I want them to be dictionaries...
>>> in_val_outs
[['KEYS', 'a set of keys', 'InsideBuilding'], ['LAMP', 'a brightly shining brass lamp', 'BeneathGrate'],...
>>>
>>> room_contents = {ivo[2]:{ivo[0]:ivo[1]} for ivo in in_val_outs}
>>> room_contents
{'InsideBuilding': {'KEYS': 'a set of keys'}, 'BeneathGrate': {'LAMP':...
- With this dictionary, if you are using an AdvRoom class, you can simply look up a room (the out key) and store the contents (the inner dictionary, of item name and description) to be the contents of the room.
- Or just store the items in AdvGame! Whatever works.
Second Example: SmallItems.txt
- We also have to be able to print, e.g., "There is an item of some import here."
- We need a "print_room_items()" or something.
def print_room_items(room_name):
contents = room_contents[room_name]
for key in contents:
print("There is", contents[key], "here.")
- This may help on Milestone 3.
Second Example: SmallItems.txt
- We can shorten the code:
room_contents = {ivo[2]:{ivo[0]:ivo[1]} for ivo in [item.split("\n") for item in open("SmallItems.txt").read().split("\n\n")]}
def print_room_items(room_name):
[print("There is", val, "here.") for key, val in room_contents[room_name].items()]
- This may help on Milestone 3.
Announcements
- Adventure Ongoing
- At least finish Milestone 0: TM -> ADV, to give your brain time to think
- Advising ongoing
- If you encounter any problem, email me immediately
- I'll be doing triage:
- If you don't get an email back quickly, either
- the problem is not urgent and I'll solve it latter, or
- I am fleeing a zamboni IRL and require thoughts & prayers stat.