Never Walk Alone

An easy Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.

Domain
Python
Difficulty
easy
Seniority
L3
Asked in
JPMorgan Chase

Problem

Which adjacent word pairs does a raw search query in text contain, in the order they appear? Queries come straight from the request log, so words can be separated by tabs or runs of spaces, and that spacing never forms a word of its own.

Every step is measured against the one before it.

Example 1

Input:

text = "the quick brown fox"

Output:

[["the","quick"],["quick","brown"],["brown","fox"]]

Example 2

Input:

text = "hello world"

Output:

[["hello","world"]]

Worked solution and explanation

Strip the costume and this is bigram extraction: every adjacent pair of tokens, overlapping, from text whose spacing you do not control. The pairing is the easy part. The problem lives in two decisions that look cosmetic. The first is tokenizing. text.split(' ') treats each single space as a delimiter, so a tab stays glued inside a token, a double space manufactures an empty word, and 'sun\tmoon stars' comes back with pairs no grader accepts. The second is the bound. Walk to len(words) instead of len(words) - 1 and the last step reads words[i + 1] off the end. That is an IndexError on exactly the boundary input an interviewer hands you.

How a senior reasons through it

Step 1: Tokenize on any whitespace run

words = text.split(). Pick it deliberately over split(' '): the log has tabs and double spaces, and the bare call makes runs of whitespace a non-issue instead of a bug you patch later with an if word filter.

Step 2: Pair each word with its right-hand neighbor

range(len(words) - 1) gives every start index that has a neighbor. Each interior word appears twice, as the right of one pair and the left of the next. Stepping two at a time instead silently drops every pair that straddles a chunk boundary.

Step 3: Let the bound absorb short inputs

No special case for an empty or one-word query. With zero or one word, len(words) - 1 is -1 or 0, the range is empty, the loop never runs, and the function returns []. The edge is handled by the bound, not by a guard you could forget.

Adjacent pairs over whitespace tokens
def sequential_word_pairs(text):
    words = text.split()
    result = []
    for i in range(len(words) - 1):
        pair = [words[i], words[i + 1]]
        result.append(pair)
    return result

Bare split() to tokenize; range(len(words) - 1) makes the short-input case disappear.

Literal single-space split
'sun\tmoon stars'.split(' ') gives ['sun\tmoon', '', 'stars']. The tab stays inside a token and the double space yields ''. An empty query gives [''], which has length 1, not 0.
Bare whitespace split
'sun\tmoon stars'.split() gives ['sun', 'moon', 'stars']. Runs collapse, edges trim, and ''.split() is []. The line of code is no longer, and none of the failure modes remain.

Common follow-up questions