# The Resume Sifter

> Pull what's useful. Skip what you know.

Canonical URL: <https://datadriven.io/problems/the_resume_sifter>

Domain: Python · Difficulty: medium · Seniority: L3 · Asked in: Meta

## Problem

Given a list of URLs in the format 'https://resumes.io/firstname_lastname_id' (or 'firstname_id' for single-name variants) and a set existing_ids of known ID strings, return a list of [name_prefix, id] pairs for URLs whose id is NOT in existing_ids, preserving input order. The name_prefix is everything before the LAST underscore; the id is what follows it. Each result pair must be a list of two strings, e.g. ['john_doe', '123'].

## Example

Input:

```
urls = ["https://resumes.io/john_doe_123","https://resumes.io/jane_smith_456","https://resumes.io/bob_789"], existing_ids = ["456"]
```

Output:

```
[["john_doe","123"],["bob","789"]]
```

## Worked solution and explanation

### Why this problem exists in real interviews

This tests **URL parsing, string extraction, and set-based filtering**, a practical combination in ETL workflows. Interviewers check whether candidates can extract structured data from URLs and filter against a known set.

---

### Break down the requirements

#### Step 1: Parse the URL to extract the path segment

Split on `/` to get the last path segment containing `firstname_lastname_id`.

#### Step 2: Split the segment into `name_prefix` and ID

The id is the token after the LAST underscore. Use `segment.rsplit('_', 1)` so a name containing underscores (e.g. `john_doe`) stays intact as the `name_prefix` while the trailing token becomes the id.

#### Step 3: Filter out known IDs

Check each extracted ID against the provided set of known IDs. Keep only new candidates, appending each as a `[name_prefix, id]` list and preserving input order.

---

### The solution

**URL parsing with set-based filtering**

```python
def filter_new_resumes(urls, existing_ids):
    existing = set(existing_ids)
    result = []
    for url in urls:
        segment = url.rstrip('/').split('/')[-1]
        name_prefix, candidate_id = segment.rsplit('_', 1)
        if candidate_id not in existing:
            result.append([name_prefix, candidate_id])
    return result
```

> **Time and Space Complexity**
>
> **Time:** O(n) where n is the number of URLs. Set membership check is O(1).
> 
> Space: O(k) where k is the number of new candidates.

> **Interviewers Watch For**
>
> Do you use set membership (`in existing_ids`) rather than list membership? This is the O(1) vs O(m) distinction that interviewers specifically look for.

> **Common Pitfall**
>
> Splitting the whole segment on every `_` and assuming a fixed number of parts breaks on names with underscores. Use `rsplit('_', 1)` to peel off only the trailing id, and `rstrip('/')` to tolerate a trailing slash.

---

## Common follow-up questions

- What if names could have multiple underscores (e.g., `firstname_middle_lastname_id`)? _(Tests using `rsplit('_', 1)` to split from the right for the ID.)_
- What if URLs had query parameters? _(Tests using `urllib.parse.urlparse` for robust URL parsing.)_
- How would you also deduplicate across the incoming batch? _(Tests adding extracted IDs to a running seen set.)_
- What if the `known_ids` set had millions of entries? _(Tests that sets handle this efficiently in Python with O(1) lookups.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/the_resume_sifter)
- [Python Interview Questions](https://datadriven.io/python-interview-questions)
- [Data Engineering Interview Prep Guide](https://datadriven.io/data-engineer-interview-prep)
- [Daily Challenge](https://datadriven.io/daily)

---

Source: DataDriven (https://datadriven.io). DataDriven is the data engineering interview community. Live code execution in SQL, Python, and Spark sandboxes. Every feature is open to every member.