Read Both Ways

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
junior
Asked in
Tata Consultancy Services

Problem

We sweep production records for placeholder identifiers that QA seeds as values reading the same forwards and backwards, so they are easy to spot and purge later. Scan a batch of tokens and return the ones that still read the same in both directions once you ignore case and any character that is not a letter or digit, keeping them in the order they appeared. A token with no letters or digits at all does not count.

Placeholders hide in plain sight. The symmetric ones give themselves away.

Example 1

Input:

tokens = ["Race-car","data2024","A man, a plan","Level"]

Output:

["Race-car","Level"]

Example 2

Input:

tokens = ["!!!","x","noon"]

Output:

["x","noon"]

Worked solution and explanation

What this is really testing

Strip the QA-placeholder costume and this is a filter with a normalization step hiding inside a symmetry check. Anyone can write the reverse-compare; the part that actually separates candidates is recognizing that the raw token is not what you compare. 'Race-car' is not equal to its own reverse as a raw string, and '!!!' looks symmetric but carries no real value. The candidate who normalizes first (case-fold, keep only letters and digits) and then guards against the empty result gets the right set. The one who writes the one-liner over raw strings misses real flags and invents fake ones.


Break down the requirements

Step 1: Normalize each token before judging it

Lowercase every character and keep only the ones where c.isalnum() is true. This is the load-bearing step: it turns 'Race-car' into 'racecar' so the comparison can succeed, and it is what a raw reverse-compare skips.

Step 2: Compare the cleaned form to its reverse

Once normalized, cleaned == cleaned[::-1] is the symmetry test. Slicing with [::-1] reverses the string in one expression and reads exactly like the spec sentence.

Step 3: Reject tokens that normalize to nothing

A token like '!!!' becomes the empty string after normalization, and the empty string equals its own reverse, so without a guard it would be flagged. The prompt says a token with no letters or digits does not count, so require cleaned to be non-empty.

Step 4: Append the ORIGINAL token, in order

Collect the untouched input token, not its normalized form, and append as you walk the list so input order is preserved for free.


The solution

Normalize, then mirror-compare
def find_palindromes(tokens):
    flagged = []
    for token in tokens:
        cleaned = "".join(c.lower() for c in token if c.isalnum())
        if cleaned and cleaned == cleaned[::-1]:
            flagged.append(token)
    return flagged

Common follow-up questions