Determine if all the phrases are found within the input string.
If they're all found (using distance as a measure of leeway) return True. Else False.
Example:
- input = 'can i go to the bathroom in the morning',
- phrases = ['can go', 'bathroom morning']
- if distance is 1 then this won't result in a match because
- 'bathroom', 'morning' has 2 words between it
- if distance is 2 then 'bathroom in the morning' is counted as a valid phrase
Code improvement questions
- How would you make the code more readable
- How do they handle punctuation - do they distinguish between types of punctuation and why How do they handle stemming?
- Do they handle overlapping instances and partial phrase matches (need to check them all)
- Big O time/ best/worst case scenarios
def get_compound_keyword_match(input: str, phrases: list, distance: int) -> bool:
if not distance:
# We have no leeway for a match.
if all(phrase in input for phrase in phrases):
return True
keywords = input.split()
for phrase in phrases:
phrase_matched = False
ck_words = phrase.split()
first_word_matches = [
i for i, x in enumerate(keywords) if x == ck_words[0]
]
if not first_word_matches:
return False
for first_word_match in first_word_matches:
old_match_index = first_word_match
matched = False
for i in range(0, len(ck_words)):
try:
match_index = keywords.index(ck_words[i])
if match_index - old_match_index > (distance + 1):
matched = False
old_match_index = match_index
except ValueError:
matched = False
if matched:
phrase_matched = True
break
if not phrase_matched:
return False
return True
Some unittests
class TestCompoundKeywords(unittest.TestCase):
""" Runnable compound keyword unittests.
"""
def test_valid_match(self):
"""finds a valid compound keyword"""
self.assertTrue(
get_compound_keyword_match(
"can i take tylenol", ["take tylenol"], 0,
)
)
def test_invalid_match(self):
"""finds multiple keywords in entry"""
self.assertTrue(
get_compound_keyword_match(
"can i take a tylenol take tylenol", ["take", "tylenol"], 1,
)
)
def test_ck_valid_match(self):
"""finds a valid compound keyword match with distance > 1"""
self.assertTrue(
get_compound_keyword_match(
"can i take a big tylenol", ["take tylenol"], 2,
)
)
def test_multiple_ck_valid_match(self):
"""Contains two compound keyword matches with distance <= 2"""
self.assertTrue(
get_compound_keyword_match(
"can i take a big tylenol i have severe allergies", ["take tylenol", "have allergies"], 2,
)
)
def test_multiple_ck_invalid_distance_match(self):
"""Assert that if not all compound keywords are matchable within distance we fail"""
self.assertFalse(
get_compound_keyword_match(
"can i take a big tylenol i have severe allergies", ["take tylenol", "have allergies"], 1,
)
)
def test_invalid_match_duplicate_words(self):
"""Assert that an unmatchable phrase fails"""
self.assertFalse(
get_compound_keyword_match(
"if i am nauseous and if i am coughing can i take tylenol", ["i i nauseous i"], 5,
)
)
if __name__ == "__main__":
unittest.main()