- Start with an informal English (or Portuguese or Swahili, etc.) description
of what you want the function to do, and name it.
-
The function should take a word and determine whether it has consonants and vowels in particular specified positions.
-
I'll call it "word_agrees_char_template".
- Decide whether your function should return something and, if so, what the return type is.
- This function tells whether, so it should return a boolean.
-
Come up with some informal examples of how the function should behave.
word_agrees_char_template("ago", "V at 0, V at 2") => True
word_agrees_char_template("ago", "V at 0, V at 2, C at 1") => True
word_agrees_char_template("ago", "C at 0, V at 2") => True
word_agrees_char_template("go", "V at 1, C at 0, V at 2") => False
word_agrees_char_template("both", "C at 0, V at 1, C at 3") => True
word_agrees_char_template("both", "C at 0, V at 1, C at 3") => True
word_agrees_char_template("both", "C at 0, V at 1, C at 3, V at 2") => False
-
Figure out how you'll represent the arguments to the function, that is, what data types you'll use.
-
A word is a sequence of characters, and the function doesn't have to mutate the word,
so I can represent it using a string.
-
The character template is a sequence of sets of characters and positions, and the function doesn't have to mutate the pattern, so I can represent it as a tuple (or list) of pairs consisting of character sets and positions.
Each pair can be a tuple (or list) of a string and an int (the position),
for example, ('aeiou', 0).
- If there is data that you'll be using over and over, consider treating is as constants, assigning a global variable to each.
-
Make your examples more formal by representing the arguments using the types and constants you decided on.
word_agrees_char_template("ago", ( (VOW, 0), (VOW, 2), (CONS, 1) )) => True
word_agrees_char_template("both", ( (CONS, 0), (VOW, 1), (CONS, 3), (VOW, 2) )) => False
-
Generalize over your examples, giving sensible parameter names to the arguments, and start your definition.
def word_agrees_char_template(word, char_template):
'''word: a string, char_template: a tuple of (strings, int) tuples.'''
# ...
# return True/False
- Think informally about how you would solve a couple of your examples.
-
word_agrees_char_template("ago", ( (VOW, 0), (VOW, 2), (CONS, 1) ))
- First I check the first pair in the
char_template to see if it agrees with the word:
the character in the 0th position in "ago", "a", is in VOW.
- Next I check the second pair in the
char_template for the same thing:
the character in the 2nd positionin "ago", "o", is in VOW.
- Next I check the third pair and see that the character in the 1st position, "g", is in
CONS.
- There aren't any more conditions to check for, and all of them passed, so I return
True.
-
word_agrees_char_template("ago", ( (CONS, 0), (VOW, 2) ))
- First I check the first pair in the
char_template to see if it agrees with the word:
the character in the 0th position in "ago", "a", is not in CONS.
- I don't have to check any further because all of the conditions have to be satisfied, so I return
False right away.
- Ask yourself whether there are different cases in your program, and think about how you can handle each one.
- There are two cases
- When all of the conditions have been satisfied, return
True.
- As soon as one of the conditions is not satisfied, return
False.
- We can handle the two different cases with separate
return statements;
the one returning False comes earlier because it happens sooner.
def word_agrees_char_template(word, char_template):
'''word: a string, char_template: a tuple of (strings, int) tuples.'''
# ...
# Some condition in char_template is not satisfied...
return False
# ...
# All the conditions have been satisfied, so...
return True
- Decide whether there is a value that you will need several times. If so, assign a local variable to it.
- For this problem, there is no such value.
- Ask yourself whether you were doing the "same thing" when you simulated the function.
If so, your definition needs a loop.
-
If you are doing the same thing with each of the items in a sequence, use a
for
loop; otherwise, use a while loop.
- Yes, I was repeatedly doing the same thing with the items in the sequence
char_template:
asking whether the character in the word in the given position (the second subitem of the sequence item)
was in the character set (the first subitem of the sequence item).
So I should use a for loop.
-
If you're using a
for loop, write the header.
The variable represents each item in the sequence.
Or if each item is a sequence and you're using the subitems, you can use a variable for each.
- Write the body of the loop, including everything that happens every time through the loop,
expressing this in terms of the local variables in the function.
You may need more local variables if there are values that you're going to use more than once.
You may also want to define a separate function for all or part of what happens inside the loop,
especially if this is something you may want to use elsewhere.
- Each time through the loop, I need to check whether the character in
position in word is in chars.
I'll write a separate function for this.
def word_agrees_chars(word, chars, position):
"""Are any of chars in position in word?"""
return word[position] in chars
-
Now I'll call this function in the body of the loop. If it's
False,
I return False immediately.
for chars, position in char_template:
if not word_agrees_chars(word, chars, position):
return False
- Put it all together, and test it on your examples.
def word_agrees_char_template(word, char_template):
"""Are all char and position constraints in char_pos satisfied in seq?"""
for chars, pos, in char_template:
if not word_agrees_chars(word, chars, pos):
return False
return True
>>> word_agrees_char_template("ago", ( (VOW, 0), (VOW, 2), (CONS, 1) ))
True
>>> word_agrees_char_template("both", ( (CONS, 0), (VOW, 1), (CONS, 3), (VOW, 2) ))
False